<!DOCTYPE html>
<html>

<head>
  <meta charset='utf-8'>
  <title>关键点</title>
  <link rel="shortcut icon" href="../icon/sparrow.png" />
  <link rel="bookmark" href="../icon/sparrow.png" type="image/x-icon" />
  <link rel="stylesheet" href="../styles/common.css" />
  <!-- 对于制作原型或学习，你可以这样使用最新版本： -->
  <script src="https://cdn.jsdelivr.net/npm/vue/dist/vue.js"></script>
</head>

<body>
  <div class="sticky-title">
    <!-- 伟大、无私、正经的 黄橙 先生存笔记于此 -->
    JS入门要点笔记
  </div>
  <div class="content-container">
    <div class="chapter-box">

      <!-- call、apply、bind方法 -->
      <div class="chapter" id='kp1'>
        <h2>kp1 call、apply、bind方法</h2>
        <pre>
  1、js中的call、apply方法
    1）bind是返回对应函数，便于之后调用；apply、call则是立即调用
    2）在js中，call和apply都是为改变某个函数运行时上下文而存在的，也即改变this的指向
      js中，函数存在：定义时上下文、运行时上下文，并且上下文是可以改变的
      call 和 apply 是为了动态改变 this 而出现的，当一个 object 没有某个方法
        但是其他的有（本栗子中apple有say方法），我们可以借助call或apply用其它对象的方法来操作。
    3）对于 apply、call 二者而言，作用完全一样，只是接受参数的方式不太一样。
      call 需要把参数按顺序传递进去，而 apply 则是把参数放在数组里。
      arguments参数是个伪数组，通过 Array.prototype.slice.call 转化为标准数组<code>
                    function log(){
                      var args = Array.prototype.slice.call(arguments);
                      args.unshift('(app)');
                      console.log.apply(console, args);
                    };</code>
      Javascript中存在一种名为伪数组的对象结构。
        比较特别的是 arguments 对象，还有像调用 getElementsByTagName , document.childNodes 之类的，
        它们返回NodeList对象都属于伪数组。不能应用 Array下的 push , pop 等方法。
        但是我们能通过 Array.prototype.slice.call 转换为真正的数组的带有 length 属性的对象，
        这样 domNodes 就可以应用 Array 下的所有方法了。
  2、js中的bind方法
    1）bind()最简单的用法是创建一个函数，使这个函数不论怎么调用都有同样的this值。
      常见的错误就像上面的例子一样，将方法从对象中拿出来，然后调用，并且希望this指向原来的对象。
      如果不做特殊处理，一般会丢失原来的对象。使用bind()方法能够很漂亮的解决这个问题
    2）bind() 方法与 apply 和 call 很相似，也是可以改变函数体内 this 的指向。
    3）MDN的解释是：bind()方法会创建一个新函数，称为绑定函数。
      当调用这个绑定函数时，绑定函数会以创建它时传入 bind()方法的第一个参数作为 this，
      传入 bind() 方法的第二个以及以后的参数加上绑定函数运行时本身的参数按照顺序作为原函数的参数来调用原函数。<code>
                    var foo = {
                      bar : 1,
                      eventBind: function(){
                          $('.someClass').on('click',function(event) {
                              console.log(this.bar);      //1
                          }.bind(this));
                      }
                    }</code>
      在上述代码里，bind() 创建了一个函数，当这个click事件绑定在被调用的时候，
        它的 this 关键词会被设置成被传入的值（这里指调用bind()时传入的参数）。
        因此，这里我们传入想要的上下文 this(其实就是 foo )，到 bind() 函数中。
        然后，当回调函数被执行的时候， this 便指向 foo 对象。
  3、偏函数（Partial Functions）
    Partial application can be described as taking a function that accepts some number of arguments, 
      binding values to one or more of those arguments, and returning a new function that only accepts 
      the remaining, un-bound arguments.
    使用bind()我们设定函数的预定义参数，然后调用的时候传入其他参数即可
    偏函数是 JS 函数柯里化运算的一种特定应用场景。
      简单描述，就是把一个函数的某些参数先固化，也就是设置默认值，返回一个新的函数，
      在新函数中继续接收剩余参数，这样调用这个新函数会更简单。<code>
                    const log = (...arguments) => console.log.apply(console, arguments); // apply传入的是对象和数组，箭头函数没有arguments
                    const allxLog = log.bind(undefined, `[ALLX(${Date.now()})]: `); // undefined后的参数作为bind返回函数的参数 
                    allxLog("hello"); // [ALLX(1581906826286)]:  hello</code>
  4、bind()也可以为需要特定this值的函数创造捷径
    例如要将一个类数组对象转换为真正的数组，如果使用bind()的话，情况变得更简单：<code>
                    const slice = Function.prototype.call.bind(Array.prototype.slice);
                    slice(arguments);</code>
  5、柯里化函数相比于不同函数更加高效，简洁。
　　柯里化函数由于只有一个参数，在运行时会读取缓存，因而可以提高性能
  6、当你希望改变上下文环境之后并非立即执行，而是回调执行的时候，使用 bind() 方法。而 apply/call 则会立即执行函数。
  7、总结
    apply 、 call 、bind 三者都是用来改变函数的this对象的指向的；
    apply 、 call 、bind 三者第一个参数都是this要指向的对象，也就是想指定的上下文；
    apply 、 call 、bind 三者都可以利用后续参数传参；
    bind 是返回对应函数，便于稍后调用；apply 、call 则是立即调用 。
</pre>
      </div>

      <!-- js基本语法 -->
      <div class="chapter" id='kp2'>
        <h2>kp2 js基本语法</h2>
        <pre>
  1、语句、表达式
    前者主要为了进行某种操作，一般情况下不需要返回值；后者则是为了得到返回值，一定会返回一个值。
    表达式不需要分号结尾。一旦在表达式后面添加分号，则 JavaScript 引擎就将表达式视为语句。
  2、变量
    1）如果只是声明变量而没有赋值，则该变量的值是undefined
    2）JavaScript 是一种动态类型语言，也就是说，变量的类型没有限制，变量可以随时更改类型。
    3）变量提升：
      JavaScript 引擎的工作方式是，先解析代码，获取所有被声明的变量，然后再一行一行地运行；
      这造成的结果，就是所有的变量的声明语句，都会被提升到代码的头部，这就叫做变量提升（hoisting）。
  3、标识符
    第一个字符，可以是任意 Unicode 字母（包括英文字母和其他语言的字母），以及π、美元符号（$）和下划线（_）。
    第二个字符及后面的字符，除了 Unicode 字母、美元符号和下划线，还可以用数字0-9。
    中文是合法的标识符，可以用作变量名。
    JavaScript 有一些保留字，不能用作标识符：arguments、break、case、catch、class、const、continue、
      debugger、default、delete、do、else、enum、eval、export、extends、false、finally、for、function、
      if、implements、import、in、instanceof、interface、let、new、null、package、private、protected、
      public、return、static、super、switch、this、throw、true、try、typeof、var、void、while、with、yield。
  4、注释
    JavaScript 提供两种注释的写法：一种是单行注释，用//起头；另一种是多行注释，放在/*和*/之间。
  5、区块
    JavaScript 使用大括号，将多个相关的语句组合在一起，称为“区块”（block）。
    对于var命令来说，JavaScript 的区块不构成单独的作用域（scope），与不使用区块的情况没有任何区别。
  6、条件语句
    JavaScript 提供if结构和switch结构，完成条件判断，即只有满足预设的条件，才会执行相应的语句。
      1）注意，if后面的表达式之中，不要混淆赋值表达式（=）、严格相等运算符（===）和相等运算符（==）。
        else代码块总是与离自己最近的那个if语句配对。
        如果所有case都不符合，则执行最后的default部分。
      2）需要注意的是，每个case代码块内部的break语句不能少，否则会接下去执行下一个case代码块，而不是跳出switch结构。
        case代码块之中没有break语句，导致不会跳出switch结构，而会一直执行下去。
        switch语句部分和case语句部分，都可以使用表达式。
        switch语句后面的表达式，与case语句后面的表示式比较运行结果时，采用的是严格相等运算符（===），
          而不是相等运算符（==），这意味着比较时不会发生类型转换。
      3）三元运算符：(条件) ? 表达式1 : 表达式2
  7、循环语句
    1）While语句包括一个循环条件和一段代码块，只要条件为真，就不断循环执行代码块。
    2）for语句是循环命令的另一种形式，可以指定循环的起点、终点和终止条件。
      所有for循环，都可以改写成while循环。
    3）do...while循环与while循环类似，唯一的区别就是先运行一次循环体，然后判断循环条件。
    4）break语句和continue语句都具有跳转作用，可以让代码不按既有的顺序执行。
      break语句用于跳出代码块或循环。
      continue语句用于立即终止本轮循环，返回循环结构的头部，开始下一轮循环。
    5）标签
      JavaScript 语言允许，语句的前面有标签（label），相当于定位符，用于跳转到程序的任意位置，标签的格式如下。
      标签可以是任意的标识符，但不能是保留字，语句部分可以是任意语句。
      标签通常与break语句和continue语句配合使用，跳出特定的循环。
</pre>
      </div>

      <!-- js数据类型 -->
      <div class="chapter" id='kp3'>
        <h2>kp3 js数据类型</h2>
        <pre>
  1、JavaScript 的数据类型，共有六种。
    数值（number）：整数和小数（比如1和3.14）
    字符串（string）：文本（比如Hello World）。
    布尔值（boolean）：表示真伪的两个特殊值，即true（真）和false（假）
    undefined：表示“未定义”或不存在，即由于目前没有定义，所以此处暂时没有任何值
    null：表示空值，即此处的值为空。
    对象（object）：各种值组成的集合。
      对象是最复杂的数据类型，又可以分成三个子类型。
        狭义的对象（object）
        数组（array）
        函数（function）
          函数其实是处理数据的方法，JavaScript 把它当成一种数据类型，可以赋值给变量，
            为编程带来了很大的灵活性，也为 JavaScript 的“函数式编程”奠定了基础。
    数值、字符串、布尔值这三种类型，合称为原始类型（primitive type）的值，是最基本的数据类型，不能再细分了。
    对象则称为合成类型（complex type）的值，因为一个对象往往是多个原始类型的值的合成，可以看作是一个存放各种值的容器。
    undefined和null，一般将它们看成两个特殊值。
  2、typeof运算符
    JavaScript 有三种方法，可以确定一个值到底是什么类型。
      typeof运算符、instanceof运算符、Object.prototype.toString方法
    typeof运算符可以返回一个值的数据类型。
      number、string、boolean、function、undefined、object（null也是object）
    undefined返回undefined。利用这一点，typeof可以用来检查一个没有声明的变量，而不报错，通常用在判断语句。
    null返回object。这是由于历史原因造成的
</pre>
      </div>

      <!-- js的null和undefined -->
      <div class="chapter" id='kp4'>
        <h2>kp4 js的null和undefined</h2>
        <pre>
  1、null与undefined都可以表示“没有”
    在if语句中，它们都会被自动转为false，相等运算符（==）甚至直接报告两者相等。
    区别是这样的：null是一个表示“空”的对象，转为数值时为0；undefined是一个表示"此处无定义"的原始值，转为数值时为NaN。
      Number(undefined) // NaN
  2、null表示空值，即该处的值现在为空。
  3、undefined表示“未定义”：
    变量声明了，但没有赋值
    调用函数时，应该提供的参数没有提供，该参数等于 undefined
    对象没有赋值的属性
    函数没有返回值时，默认返回 undefined
  4、布尔值代表“真”和“假”两个状态。“真”用关键字true表示，“假”用关键字false表示。布尔值只有这两个值。
    前置逻辑运算符： ! (Not)、相等运算符：===，!==，==，!=、比较运算符：>，>=，<，<=
    JavaScript 预期某个位置应该是布尔值，会将该位置上现有的值自动转为布尔值
    转换规则是除了下面六个值被转为false，其他值都视为true。
      undefined、null、false、0、NaN、''（空字符串）
</pre>
      </div>

      <!-- js的数值类型 -->
      <div class="chapter" id='kp5'>
        <h2>kp5 js的数值类型</h2>
        <pre>
  1、JavaScript 内部，所有数字都是以64位浮点数形式储存，即使整数也是如此。所以，1与1.0是相同的，是同一个数。
    JavaScript 语言的底层根本没有整数，所有数字都是小数（64位浮点数）。
    某些运算只有整数才能完成，此时 JavaScript 会自动把64位浮点数，转成32位整数，然后再进行运算。
    由于浮点数不是精确的值，所以涉及小数的比较和运算要特别小心。
    JavaScript 提供Number对象的MAX_VALUE和MIN_VALUE属性，返回可以表示的具体的最大值和最小值。
      Number.MAX_VALUE // 1.7976931348623157e+308
      Number.MIN_VALUE // 5e-324
  2、使用字面量（literal）直接表示一个数值时，JavaScript 对整数提供四种进制的表示方法：
    十进制：没有前导0的数值。
    十六进制：有前缀0x或0X的数值。
    八进制：有前缀0o或0O的数值，或者有前导0、且只用到0-7的八个阿拉伯数字的数值。
    二进制：有前缀0b或0B的数值。
    默认情况下，JavaScript 内部会自动将八进制、十六进制、二进制转为十进制。
    前导0表示八进制，处理时很容易造成混乱。ES5 的严格模式和 ES6，已经废除了这种表示法，
      但是浏览器为了兼容以前的代码，目前还继续支持这种表示法。
  3、特殊数值
    1）JavaScript 内部实际上存在2个0：一个是+0，一个是-0，区别就是64位浮点数表示法的符号位不同。
      几乎所有场合，正零和负零都会被当作正常的0。唯一有区别的场合是，+0或-0当作分母，返回的值是不相等的。
    2）NaN是 JavaScript 的特殊值，表示“非数字”（Not a Number），主要出现在将字符串解析成数字出错的场合。
      NaN不等于任何值，包括它本身。NaN在布尔运算时被当s作false。NaN与任何数（包括它自己）的运算，得到的都是NaN。
    3）Infinity表示“无穷”，用来表示两种场景。
      一种是一个正的数值太大，或一个负的数值太小，无法表示；
      另一种是非0数值除以0，得到Infinity。
      Infinity有正负之分，Infinity表示正的无穷，-Infinity表示负的无穷。
      Infinity大于一切数值（除了NaN），-Infinity小于一切数值（除了NaN）。
  4、与数值相关的全局方法
    1）parseInt：将字符串转为整数。如果parseInt的参数不是字符串，则会先转为字符串再转换。
      返回值只有两种可能，要么是一个十进制整数，要么是NaN。
      parseInt方法还可以接受第二个参数（2到36之间），表示被解析的值的进制，返回该值对应的十进制数。
        此时的第一个参数必须为该进制
    2）parseFloat：将一个字符串转为浮点数。
    3）isNaN：判断一个数值是否为NaN。
      isNaN只对数值有效，如果传入其他值，会被先转成数值。
    4）isFinite：返回一个布尔值，表示某个值是否为正常的数值。
      除了Infinity、-Infinity、NaN和undefined这几个值会返回false，isFinite对于其他的数值都会返回true。
</pre>
      </div>

      <!-- js的字符串 -->
      <div class="chapter" id='kp6'>
        <h2>kp6 js的字符串</h2>
        <pre>
  1、反斜杠（\）在字符串内有特殊含义，用来表示一些特殊字符，所以又称为转义符。
  2、字符串可以被视为字符数组，因此可以使用数组的方括号运算符，用来返回某个位置的字符（位置编号从0开始）。
    无法改变字符串之中的单个字符。无法改变和增删
  3、length属性返回字符串的长度，该属性也是无法改变的。
  4、JavaScript 使用 Unicode 字符集。JavaScript 引擎内部，所有字符都用 Unicode 表示。
    JavaScript 不仅以 Unicode 储存字符，还允许直接在程序中使用 Unicode 码点表示字符，
      即将字符写成\uxxxx的形式，其中xxxx代表该字符的 Unicode 码点。\u00A9 -- 版权符<span>"©"</span>
      解析代码的时候，JavaScript 会自动识别一个字符是字面形式表示，还是 Unicode 形式表示。
      输出给用户的时候，所有字符都会转成字面形式。
  5、Base64转码：Base64 就是一种编码方法，可以将任意值转成 0～9、A～Z、a-z、+和/这64个字符组成的可打印字符。
    为了不出现特殊字符，简化程序的处理。
    文本里面包含一些不可打印的符号，可以使用 Base64 编码，将它们转成可以打印的字符。
    有时需要以文本格式传递二进制数据，那么也可以使用 Base64 编码。
    ·btoa()：任意值转为 Base64 编码
    ·atob()：Base64 编码转为原来的值
    不适合非 ASCII 码的字符，会报错。
    要将非 ASCII 码字符转为 Base64 编码，必须中间插入一个转码环节，再使用这两个方法。
</pre>
      </div>

      <!-- js的对象 -->
      <div class="chapter" id='kp7'>
        <h2>kp7 js的对象</h2>
        <pre>
  1、简单说，对象就是一组“键值对”（key-value）的集合，是一种无序的复合数据集合。
  2、对象的所有键名都是字符串（ES6 又引入了 Symbol 值也可以作为键名），所以加不加引号都可以。
    如果键名是数值，会被自动转为字符串。
  3、对象的每一个键名又称为“属性”（property），它的“键值”可以是任何数据类型。
    如果一个属性的值为函数，通常把这个属性称为“方法”，它可以像函数那样调用。
    如果属性的值还是一个对象，就形成了链式引用。
    属性可以动态创建，不必在对象声明时就指定。
  4、对象的引用
    如果不同的变量名指向同一个对象，那么它们都是这个对象的引用，也就是说指向同一个内存地址。
    修改其中一个变量，会影响到其他所有变量。
    引用只局限于对象，如果两个变量指向同一个原始类型的值。那么，变量这时都是值的拷贝。
  5、属性的操作
    点运算符、方括号运算符
    如果使用方括号运算符，键名必须放在引号里面，否则会被当作变量处理。
    方括号运算符内部还可以使用表达式。
    数字键可以不加引号，因为会自动转成字符串。只能使用方括号运算符，不能使用点运算符（因为会被当成小数点）
  6、属性的查看
    查看一个对象本身的所有属性，可以使用Object.keys方法。
  7、属性的删除
    delete命令用于删除对象的属性，删除成功后返回true。
  8、属性是否存在：in 运算符
    in运算符用于检查对象是否包含某个属性（注意，检查的是键名，不是键值），如果包含就返回true，否则返回false。
    使用对象的hasOwnProperty方法判断一下，是否为对象自身的属性。（去除掉继承来的属性）
  9、属性的遍历：for...in 循环
    遍历的是对象所有可遍历（enumerable）的属性，会跳过不可遍历的属性。
    不仅遍历对象自身的属性，还遍历继承的属性。
    使用for...in的时候，应该结合使用hasOwnProperty方法，在循环内部判断一下，某个属性是否为对象自身的属性。
  10、with语句：with (对象) { 语句; } -- 操作同一个对象的多个属性时，提供一些书写的方便。
    注意，如果with区块内部有变量的赋值操作，必须是当前对象已经存在的属性，否则会创造一个当前作用域的全局变量。
      var obj = { p1: 1, p2: 2, };
      with (obj) { p1 = 4; p2 = 5; }
    建议不要使用with语句
</pre>
      </div>

      <!-- js的函数 -->
      <div class="chapter" id='kp8'>
        <h2>kp8 js的函数</h2>
        <pre>
  1、函数的声明
    1）function命令声明的代码区块，就是一个函数。function func(函数参数) {函数体}
    2）采用变量赋值的写法。将一个匿名函数赋值给变量。
      这时，这个匿名函数又称函数表达式（Function Expression），因为赋值语句的等号右侧只能放表达式。
      var func = function(函数参数) {函数体}
      function命令后面不带有函数名。如果加上函数名，该函数名只在函数体内部有效，在函数体外部无效。
    3）Function 构造函数：var add = new Function('x', 'y', 'return x + y' );
      可以传递任意数量的参数给Function构造函数，只有最后一个参数会被当做函数体
      如果只有一个参数，该参数就是函数体。
      这种声明函数的方式非常不直观，几乎无人使用
  2、重复声明
    如果同一个函数被多次声明，后面的声明就会覆盖前面的声明。
    由于函数名的提升，前一次声明在任何时候都是无效的。
  3、第一等公民
    JavaScript 语言将函数看作一种值，与其它值（数值、字符串、布尔值等等）地位相同。
    凡是可以使用值的地方，就能使用函数。
      可以把函数赋值给变量和对象的属性，也可以当作参数传入其他函数，或者作为函数的结果返回。
    函数只是一个可以执行的值，此外并无特殊之处。
  4、函数名的提升
    JavaScript 引擎将函数名视同变量名
    采用function命令声明函数时，整个函数会像变量声明一样，被提升到代码头部。
    但是，如果采用赋值语句定义函数，JavaScript 就会报错。// TypeError: undefined is not a function
    如果同时采用function命令和赋值语句声明同一个函数，最后总是采用赋值语句的定义。
  5、函数的属性和方法
    1）name 属性：返回函数的名字。
    2）length属性返回函数预期传入的参数个数，即函数定义之中的参数个数。
    3）toString方法返回一个字符串，内容是函数的源码。
      对于那些原生的函数，toString()方法返回function (){[native code]}。
      函数内部的注释也可以返回。
  6、函数作用域
    在 ES5 的规范中，JavaScript 只有两种作用域：
      一种是全局作用域，变量在整个程序中一直存在，所有地方都可以读取；
      另一种是函数作用域，变量只在函数内部存在。
    注意，对于var命令来说，局部变量只能在函数内部声明，在其他区块中声明，一律都是全局变量。
    与全局作用域一样，函数作用域内部也会产生“变量提升”现象，变量声明都会被提升到函数体的头部。
  7、函数参数不是必需的，JavaScript 允许省略参数。
    没有办法只省略靠前的参数，而保留靠后的参数。如果一定要省略靠前的参数，只有显式传入undefined。
  8、传递方式：（参数）
    ·函数参数如果是原始类型的值（数值、字符串、布尔值），传递方式是传值传递（passes by value）。
      在函数体内修改参数值，不会影响到函数外部。
    ·如果函数参数是复合类型的值（数组、对象、其他函数），传递方式是传址传递（pass by reference）。
      传入函数的原始值的地址，因此在函数内部修改参数，将会影响到原始值。
      如果函数内部修改的，不是参数对象的某个属性，而是替换掉整个参数，这时不会影响到原始值。
  9、arguments 对象：可以在函数体内部读取所有参数。
    arguments对象包含了函数运行时的所有参数，这个对象只有在函数体内部，才可以使用。
    通过arguments对象的length属性，可以判断函数调用时到底带几个参数。
    虽然arguments很像数组，但它是一个对象。数组专有的方法（比如slice和forEach），不能在arguments对象上直接使用。
    如果要让arguments对象使用数组方法，真正的解决方法是将arguments转为真正的数组。
    arguments对象带有一个callee属性，返回它所对应的原函数。不建议使用。
  10、闭包：可以把闭包简单理解成“定义在一个函数内部的函数”
    函数与对其状态即词法环境（lexical environment）的引用共同构成闭包（closure）。
    也就是说，闭包可以让你从内部函数访问外部函数作用域。
    在JavaScript，函数在每次创建时生成闭包。
    闭包是由函数以及创建该函数的词法环境组合而成。这个环境包含了这个闭包创建时所能访问的所有局部变量。
    闭包的最大用处有两个：一个是可以读取函数内部的变量，
      另一个就是让这些变量始终保持在内存中，即闭包可以使得它诞生环境一直存在。
    闭包的另一个用处，是封装对象的私有属性和私有方法。
    注意，外层函数每次运行，都会生成一个新的闭包，而这个闭包又会保留外层函数的内部变量，所以内存消耗很大。
    闭包很有用，因为它允许将函数与其所操作的某些数据（环境）关联起来。这显然类似于面向对象编程。
    在面向对象编程中，对象允许我们将某些数据（对象的属性）与一个或者多个方法相关联。
    在循环中创建闭包：一个常见错误
    <a href="https://developer.mozilla.org/zh-CN/docs/Web/JavaScript/Closures" target="_blank">MDN闭包参阅</a>
  11、立即调用的函数表达式（IIFE）
    一是不必为函数命名，避免了污染全局变量；
    二是 IIFE 内部形成了一个单独的作用域，可以封装一些外部无法读取的私有变量。
  12、eval命令：接受一个字符串作为参数，并将这个字符串当作语句执行。
    如果eval的参数不是字符串，那么会原样返回。
    eval的本质是在当前作用域之中，注入代码。由于安全风险和不利于 JavaScript 引擎优化执行速度，所以一般不推荐使用。
    eval最常见的场合是解析 JSON 数据的字符串，不过正确的做法应该是使用原生的JSON.parse方法。
    JavaScript 的标准规定，凡是使用别名执行eval，eval内部一律是全局作用域。
</pre>
      </div>

      <!-- js的数组 -->
      <div class="chapter" id='kp9'>
        <h2>kp9 js的数组</h2>
        <pre>
  1、本质上，数组属于一种特殊的对象。typeof运算符会返回数组的类型是object。
    数组的特殊性体现在，它的键名是按次序排列的一组整数（0，1，2...）。
    JavaScript 语言规定，对象的键名一律为字符串，所以，数组的键名其实也是字符串。
    之所以数组可以用数值读取，是因为非字符串的键名会被转为字符串。
    对于数值的键名，对象读取成员不能使用点结构。
  2、数组的length属性，返回数组的成员数量。
    length属性是可写的。如果人为设置一个小于当前成员个数的值，该数组的成员会自动减少到length设置的值。
    清空数组的一个有效方法，就是将length属性设为0。
  3、检查某个键名是否存在的运算符in，适用于对象，也适用于数组。
    注意，如果数组的某个位置是空位，in运算符返回false。
  4、for...in循环不仅可以遍历对象，也可以遍历数组，毕竟数组只是一种特殊对象。
    但是，for...in不仅会遍历数组所有的数字键，还会遍历非数字键。
    数组的forEach方法，也可以用来遍历数组
  5、当数组的某个位置是空元素，即两个逗号之间没有任何值，我们称该数组存在空位（hole）。
    如果最后一个元素后面有逗号，并不会产生空位。
    使用delete命令删除一个数组成员，会形成空位，并且不会影响length属性。
    空位就是数组没有这个元素，不会被遍历到；undefined则表示数组有这个元素，值是undefined，遍历不会跳过。
  6、类似数组的对象
    一个对象的所有键名都是正整数或零，有length属性，语法上称为“类似数组的对象”（array-like object）。
    典型的“类似数组的对象”是函数的arguments对象，以及大多数 DOM 元素集，还有字符串。
    数组的slice方法可以将“类似数组的对象”变成真正的数组。
</pre>
      </div>

      <!-- js的运算符 -->
      <div class="chapter" id='kp10'>
        <h2>kp10 js的运算符</h2>
        <pre>
  1、10个算术运算符
    加法运算符：x + y
      JavaScript 允许非数值的相加。
      如果是两个字符串相加，这时加法运算符会变成连接运算符，返回一个新的字符串，将两个原字符串连接在一起。
    减法运算符： x - y
    乘法运算符： x * y
    除法运算符：x / y
    指数运算符：x ** y
    余数运算符：x % y
    自增运算符：++x 或者 x++
    自减运算符：--x 或者 x--
    数值运算符： +x
      数值运算符的作用在于可以将任何值转为数值（与Number函数的作用相同）。
    负数值运算符：-x
  2、比较运算符：比较两个值的大小，然后返回一个布尔值
      > 大于运算符
      < 小于运算符
      <= 小于或等于运算符
      >= 大于或等于运算符
      == 相等运算符
      === 严格相等运算符
      != 不相等运算符
      !== 严格不相等运算符
    ·字符串按照字典顺序进行比较。
    ·如果两个运算子都是原始类型的值，则是先转成数值再比较。
    ·如果运算子是对象，会转为原始类型的值，再进行比较。
      对象转换成原始类型的值，算法是先调用valueOf方法；如果返回的还是对象，再接着调用toString方法
    ·它们的区别是相等运算符（==）比较两个值是否相等，严格相等运算符（===）比较它们是否为“同一个值”。
      相等运算符（==）会将它们转换成同一个类型，再用严格相等运算符进行比较。
      考虑类型和值
      两个复合类型（对象、数组、函数）的数据比较时，不是比较它们的值是否相等，而是比较它们是否指向同一个地址。
    ·对象（这里指广义的对象，包括数组和函数）与原始类型的值比较时，对象转换成原始类型的值，再进行比较。
  3、布尔运算符：将表达式转为布尔值
      取反运算符：!
        对一个值连续做两次取反运算，等于将其转为对应的布尔值，与Boolean函数的作用相同。
        两次取反就是将一个值转为布尔值的简便写法。
      且运算符：&&
        且运算符（&&）往往用于多个表达式的求值。
        如果第一个运算子的布尔值为true，则返回第二个运算子的值（注意是值，不是布尔值）；
        如果第一个运算子的布尔值为false，则直接返回第一个运算子的值，且不再对第二个运算子求值。
          这种跳过第二个运算子的机制，被称为“短路”。
        多个连用：返回第一个布尔值为false的表达式的值。如果所有表达式的布尔值都为true，则返回最后一个表达式的值。
      或运算符：||
        多个表达式的求值：
          如果第一个运算子的布尔值为true，则返回第一个运算子的值，且不再对第二个运算子求值；
          如果第一个运算子的布尔值为false，则返回第二个运算子的值。
        多个连用：返回第一个布尔值为true的表达式的值。如果所有表达式都为false，则返回最后一个表达式的值。
        或运算符常用于为一个变量设置默认值。text = text || '';
      三元运算符：?:
  4、二进制位运算符：用于直接对二进制位进行计算，所有的位运算都只对整数有效。
      二进制或运算符（or）：符号为|，表示若两个二进制位都为0，则结果为0，否则为1。
        位运算只对整数有效，遇到小数时，会将小数部分舍去，只保留整数部分。
        将一个小数与0进行二进制或运算，等同于对该数去除小数部分，即取整数位。
      二进制与运算符（and）：符号为&，表示若两个二进制位都为1，则结果为1，否则为0。
      二进制否运算符（not）：符号为~，表示对一个二进制位取反。
        对一个小数连续进行两次二进制否运算，能达到取整效果。
        使用二进制否运算取整，是所有取整方法中最快的一种。
      异或运算符（xor）：符号为^，表示若两个二进制位不相同，则结果为1，否则为0。
        “异或运算”有一个特殊运用，连续对两个数a和b进行三次异或运算，a^=b; b^=a; a^=b;，可以互换它们的值。
        这是互换两个变量的值的最快方法。
        异或运算也可以用来取整。
      左移运算符（left shift）：符号为<<
      右移运算符（right shift）：符号为>>
      头部补零的右移运算符（zero filled right shift）：符号为>>>
        查看一个负整数在计算机内部的储存形式，最快的方法就是使用这个运算符。-1 >>> 0
    非常底层的运算，好处是速度极快
    位运算符只对整数起作用，如果一个运算子不是整数，会自动转为整数后再执行
    在 JavaScript 内部，数值以64位浮点数的形式储存，做位运算时，以32位带符号的整数进行运算，且返回值是32位带符号的整数。
      i = i | 0;将任意数值转为32位整数。
    位运算符可以用作设置对象属性的开关。
      假设需要打开A、B、D三个开关，我们可以构造一个掩码变量。var mask = FLAG_A | FLAG_B | FLAG_D;
  5、void 运算符：执行一个表达式，然后不返回任何值，或者说返回undefined
  6、逗号运算符：对两个表达式求值，并返回后一个表达式的值。
</pre>
      </div>

      <!-- js的数据类型转换 -->
      <div class="chapter" id='kp11'>
        <h2>kp11 js的数据类型转换</h2>
        <pre>
  1、JavaScript 是一种动态类型语言，变量没有类型限制，可以随时赋予任意值。
  2、强制转换：
    指使用Number()、String()和Boolean()三个函数，手动将各种类型的值，分别转换成数字、字符串或者布尔值。
  3、Number函数：将任意类型的值转化成数值。
  4、String函数：将任意类型的值转化成字符串
  5、Boolean函数：将任意类型的值转为布尔值。
  6、自动转换的规则是这样的：预期什么类型的值，就调用该类型的转换函数。
    建议在预期为布尔值、数值、字符串的地方，全部使用Boolean、Number和String函数进行显式转换。
</pre>
      </div>

      <!-- js的错误处理机制 -->
      <div class="chapter" id='kp12'>
        <h2>kp12 js的错误处理机制</h2>
        <pre>
  1、Error实例对象
    JavaScript 解析或运行时，一旦发生错误，引擎就会抛出一个错误对象。
    JavaScript 原生提供Error构造函数，所有抛出的错误都是这个构造函数的实例。
        var err = new Error('出错了');
    大多数JavaScript引擎的Error实例还提供name和stack属性，表示错误的名称和错误的堆栈，但非标准，不是每种实现都有。
        message：错误提示信息
        name：错误名称（非标准属性）
        stack：错误的堆栈（非标准属性）
  2、原生错误类型
    Error实例对象是最一般的错误类型，在它的基础上，JavaScript 还存在Error的6个派生对象。
    1）SyntaxError 对象：解析代码时发生的语法错误。
    2）ReferenceError对象：引用一个不存在的变量时发生的错误。
      另一种触发场景是，将一个值分配给无法分配的对象
    3）RangeError对象：值超出有效范围时发生的错误。
      主要有几种情况，一是数组长度为负数，二是Number对象的方法参数超出范围，以及函数堆栈超过最大值。
    4）TypeError对象：变量或参数不是预期类型时发生的错误
    5）URIError对象：URI相关函数的参数不正确时抛出的错误，
      涉及encodeURI()、decodeURI()、encodeURIComponent()、decodeURIComponent()、escape()和unescape()六个函数。
    6）eval函数没有被正确执行时，会抛出EvalError错误。
      该错误类型已经不再使用了，只是为了保证与以前代码兼容，才继续保留。
    以上这6种派生错误，连同原始的Error对象，都是构造函数。可以使用它们，手动生成错误对象的实例。
    这些构造函数都接受一个参数，代表错误提示信息（message）。
  3、自定义错误
          function UserError(message) {
            this.message = message || '默认信息';
            this.name = 'UserError';
          }
          UserError.prototype = new Error();
          UserError.prototype.constructor = UserError;
  4、throw语句的作用是手动中断程序执行，抛出一个错误。
          throw new Error('x 必须为正数');
    实际上，throw可以抛出任何类型的值。
    对于 JavaScript 引擎来说，遇到throw语句，程序就中止了。
  5、try...catch 结构
          try {
            throw new Error('出错了!');
          } catch (e) {
            console.log(e.name + ": " + e.message);
            console.log(e.stack);
          }
    catch代码块捕获错误之后，程序不会中断，会按照正常流程继续执行下去。
    为了捕捉不同类型的错误，catch代码块之中可以加入判断语句。if (e instanceof EvalError)
  6、finally 代码块：不管是否出现错误，都必需在最后运行的语句。
    没有catch语句块，发生错误，代码中断执行。中断执行之前，会先执行finally代码块，然后再向用户提示报错信息。
    return语句的执行是排在finally代码之前，只是等finally代码执行完毕后才返回。
    finally代码块用法的典型场景。
      在try代码块中写入文件，如果没有发生错误，则运行finally代码块关闭文件；
        一旦发生错误，则先使用catch代码块处理错误，再使用finally代码块关闭文件。
  7、抛出错误，就调到按顺序的处理模块，本处理模块的代码不再顺序执行
    catch不能顺序多个
</pre>
      </div>

      <!-- js的编码风格 -->
      <div class="chapter" id='kp13'>
        <h2>kp13 js的编码风格</h2>
        <pre>
  1、如果循环和判断的代码体只有一行，JavaScript 允许该区块（block）省略大括号。
  2、建议避免使用全局变量。如果不得不使用，可以考虑用大写字母表示变量名，这样更容易看出这是全局变量。
  3、with可以减少代码的书写，但是会造成混淆。
  4、建议不要使用相等运算符（==），只使用严格相等运算符（===）。
  5、建议不要将不同目的的语句，合并成一行。
  6、建议switch...case结构可以用对象结构代替。
</pre>
      </div>

      <!-- js的console对象与控制台 -->
      <div class="chapter" id='kp14'>
        <h2>kp14 js的console对象与控制台</h2>
        <pre>
  1、console对象是 JavaScript 的原生对象，像 Unix 系统的标准输出stdout和标准错误stderr
    可以输出各种信息到控制台，并且还提供了很多有用的辅助方法。
    常见用途有两个：调试程序，显示网页代码运行时的错误信息；提供一个命令行接口，与网页代码互动。
  2、console.log方法用于在控制台输出信息。它可以接受一个或多个参数，将它们连接起来输出。
    自动在每次输出的结尾，添加换行符。
    如果第一个参数是格式字符串，console.log方法将依次用后面的参数替换占位符，然后再进行输出。
    不同类型的数据必须使用对应的占位符：
                %s 字符串
                %d 整数
                %i 整数
                %f 浮点数
                %o 对象的链接
                %c CSS 格式字符串
    console.info是console.log方法的别名，只不过console.info方法会在输出信息的前面，加上一个蓝色图标。
    console.debug方法与console.log方法类似，会在控制台输出调试信息。
      但是，默认情况下，console.debug输出的信息不会显示，只有在打开显示级别在verbose的情况下，才会显示。
  3、console对象的所有方法，都可以被覆盖。因此，可以按照自己的需要，定义console.log方法。
  4、log方法是写入标准输出（stdout），warn方法和error方法是写入标准错误（stderr）。
  5、对于某些复合类型的数据，console.table方法可以将其转为表格显示。
  6、console.count()：count方法用于计数，输出它被调用了多少次。
    可以接受一个字符串作为参数，作为标签，对执行次数进行分类。
  7、dir方法用来对一个对象进行检查（inspect），并以易于阅读和打印的格式显示。
    对于输出 DOM 对象非常有用，因为会显示 DOM 对象的所有属性。
    Node 环境之中，还可以指定以代码高亮的形式输出。
    dirxml方法主要用于以目录树的形式，显示 DOM 节点。
  8、console.assert方法主要用于程序运行过程中，进行条件判断，如果不满足条件，就显示一个错误，但不会中断程序执行。
    两个参数，第一个参数是表达式，第二个参数是字符串。
  9、console.time()，console.timeEnd()：这两个方法用于计时，可以算出一个操作所花费的准确时间。
    它们的参数是计时器的名称。调用timeEnd方法之后，控制台会显示“计时器名称: 所耗费的时间”。
  10、console.trace方法显示当前执行的代码在堆栈中的调用路径。
  11、debugger语句主要用于除错，作用是设置断点。
    如果有正在运行的除错工具，程序运行到debugger语句时会自动停下。
    如果没有除错工具，debugger语句不会产生任何结果，JavaScript 引擎自动跳过这一句。
</pre>
      </div>

      <!-- js标准库：Object -->
      <div class="chapter" id='kp15'>
        <h2>kp15 js标准库：Object</h2>
        <pre>
  1、JavaScript 的所有其他对象都继承自Object对象，即那些对象都是Object的实例。
    Object对象的原生方法分成两类：Object本身的方法与Object的实例方法。
      ·“本身的方法”就是直接定义在Object对象的方法。Object.print = function (o) { console.log(o) };
      ·实例方法就是定义在Object原型对象Object.prototype上的方法。它可以被Object实例直接使用。
        Object.prototype.print = function () { console.log(this); };
        凡是定义在Object.prototype对象上面的属性和方法，将被所有实例对象共享就可以了。
  2、Object本身是一个函数，可以当作工具方法使用，将任意值转为对象。Object(param)
    这个方法常用于保证某个值一定是对象。
    instanceof运算符用来验证，一个对象是否为指定的构造函数的实例。
    如果参数是原始类型的值，Object方法将其转为对应的包装对象的实例
    如果Object方法的参数是一个对象，它总是返回该对象，即不用转换。
      利用这一点，可以写一个判断变量是否为对象的函数。
  3、Object构造函数的首要用途，是直接通过它来生成新对象。new Object()
    通过var obj = new Object()的写法生成新对象，与字面量的写法var obj = {}是等价的。
    Object(value)与new Object(value)两者的语义是不同的，
      Object(value)表示将value转成一个对象，
      new Object(value)则表示新生成一个对象，它的值是value。
  4、Object 的静态方法
    Object.keys方法和Object.getOwnPropertyNames方法都用来遍历对象的属性。
    Object.keys方法的参数是一个对象，返回一个数组。该数组的成员都是该对象自身非继承的所有属性名。
    Object.getOwnPropertyNames方法也是接受一个对象作为参数，返回一个数组，包含了该对象自身的所有属性名。
    Object.keys方法只返回可枚举的属性，Object.getOwnPropertyNames方法还返回不可枚举的属性名。
  5、方法定义在Object.prototype对象，称为实例方法，所有Object的实例对象都继承了这些方法。
    1）Object.prototype.valueOf()：返回一个对象的“值”，默认情况下返回对象本身。
      主要用途：JavaScript 自动类型转换时会默认调用这个方法
    2）Object.prototype.toString()：返回一个对象的字符串形式，默认情况下返回类型字符串。
      自定义toString方法，可以让对象在自动类型转换时，得到想要的字符串形式。
      数组、字符串、函数、Date 对象分别部署自定义的toString方法，覆盖了Object.prototype.toString方法。
      toString() 的应用：判断数据类型，Object.prototype.toString可以看出一个值到底是什么类型。
        可以写出一个比typeof运算符更准确的类型判断函数。
    3）Object.prototype.toLocaleString()：返回一个值的字符串形式。
      留出一个接口，让各种不同的对象实现自己版本的toLocaleString，用来返回针对某些地域的特定的值。
    4）Object.prototype.hasOwnProperty()：接受一个字符串作为参数，返回一个布尔值，表示该实例对象自身是否具有该属性。
      继承返回false
</pre>
      </div>

      <!-- js标准库：属性描述对象 -->
      <div class="chapter" id='kp16'>
        <h2>kp16 js标准库：属性描述对象</h2>
        <pre>
  1、JavaScript 提供了一个内部数据结构，用来描述对象的属性，控制它的行为，
    比如该属性是否可写、可遍历等等。
    这个内部数据结构称为“属性描述对象”（attributes object）
  2、属性描述对象提供6个元属性。
    1）value是该属性的属性值，默认为undefined。
    2）writable是一个布尔值，表示属性值（value）是否可改变（即是否可写），默认为true。
    3）enumerable是一个布尔值，表示该属性是否可遍历，默认为true。如果设为false，
      会使得某些操作（比如for...in循环、Object.keys()、JSON.stringify方法）跳过该属性。
    4）configurable是一个布尔值，表示可配置性，默认为true。
      如果设为false，将阻止某些操作改写该属性，比如无法删除该属性，也不得改变该属性的属性描述对象（value属性除外）。
      configurable属性控制了属性描述对象的可写性。
    5）get是一个函数，表示该属性的取值函数（getter），默认为undefined。
    6）set是一个函数，表示该属性的存值函数（setter），默认为undefined。
  3、Object.getOwnPropertyDescriptor()方法可以获取属性描述对象。
    第一个参数是目标对象，第二个参数是一个字符串，对应目标对象的某个属性名。
    注意，Object.getOwnPropertyDescriptor()方法只能用于对象自身的属性，不能用于继承的属性。
  4、Object.getOwnPropertyNames方法返回一个数组，成员是参数对象自身的全部属性的属性名，不管该属性是否可遍历。
    Object.keys只返回对象自身的可遍历属性的全部属性名。
  5、Object.defineProperty()方法允许通过属性描述对象，定义或修改一个属性，然后返回修改后的对象
    三个参数：object：属性所在的对象、propertyName：字符串，表示属性名、attributesObject：属性描述对象
    如果属性已经存在，Object.defineProperty()方法相当于更新该属性的属性描述对象。
    如果一次性定义或修改多个属性，可以使用Object.defineProperties()方法。
    Object.defineProperty()和Object.defineProperties()参数里面的属性描述对象，
      writable、configurable、enumerable这三个属性的默认值都为false。
  6、实例对象的propertyIsEnumerable()方法返回一个布尔值，用来判断某个属性是否可遍历。
    注意，这个方法只能用于判断对象自身的属性，对于继承的属性一律返回false。
  7、元属性：属性描述对象的各个属性称为“元属性”，因为它们可以看作是控制属性的属性。
  8、存取器：除了直接定义以外，属性还可以用存取器（accessor）定义。
    存值函数称为setter，使用属性描述对象的set属性；取值函数称为getter，使用属性描述对象的get属性。
    一旦对目标属性定义了存取器，那么存取的时候，都将执行对应的函数。
      利用这个功能，可以实现许多高级特性，比如某个属性禁止赋值。
  9、控制对象状态
    有时需要冻结对象的读写状态，防止对象被改变。
    三种冻结方法，最弱的一种是Object.preventExtensions，其次是Object.seal，最强的是Object.freeze。
    ·Object.preventExtensions方法可以使得一个对象无法再添加新的属性。
    ·Object.isExtensible方法用于检查一个对象是否使用了Object.preventExtensions方法。
    ·Object.seal方法使得一个对象既无法添加新属性，也无法删除旧属性。
      只是禁止新增或删除属性，并不影响修改某个属性的值。
    ·Object.isSealed方法用于检查一个对象是否使用了Object.seal方法。
    ·Object.freeze方法使得一个对象无法添加新属性、无法删除旧属性、也无法改变属性的值，这个对象实际上变成了常量。
    ·Object.isFrozen方法用于检查一个对象是否使用了Object.freeze方法。
    漏洞：可以通过改变原型对象，来为对象增加属性。
</pre>
      </div>

      <!-- js标准库：Array对象 -->
      <div class="chapter" id='kp17'>
        <h2>kp17 js标准库：Array对象</h2>
        <pre>
  1、Array构造函数有一个很大的缺陷，就是不同的参数，会导致它的行为不一致。
    不建议使用它生成新数组，直接使用数组字面量是更好的做法。
  2、静态方法
    Array.isArray方法返回一个布尔值，表示参数是否为数组。
    typeof运算符只能显示数组的类型是Object，而Array.isArray方法可以识别数组。
  3、实例方法：
    1）valueOf()，toString()
    2）push()，pop()
      push方法用于在数组的末端添加一个或多个元素，并返回添加新元素后的数组长度。改变原数组。
      pop方法用于删除数组的最后一个元素，并返回该元素。改变原数组。
        push和pop结合使用，就构成了“后进先出”的栈结构（stack）。
    3）shift()，unshift()
      shift()方法用于删除数组的第一个元素，并返回该元素。改变原数组。
        push()和shift()结合使用，就构成了“先进先出”的队列结构（queue）。
      unshift()方法用于在数组的第一个位置添加一个或多个元素，并返回添加新元素后的数组长度。改变原数组。
    4）join()
      以指定参数作为分隔符，将所有数组成员连接为一个字符串返回。如果不提供参数，默认用逗号分隔。
    5）concat() 
      用于多个数组的合并。将新数组的成员，添加到原数组成员的后部，然后返回一个新数组，原数组不变。
      如果数组成员包括对象，concat方法返回当前数组的一个浅拷贝。
    6）reverse() 颠倒排列数组元素，返回改变后的数组。改变原数组。
    7）slice() 提取目标数组的一部分，返回一个新数组，原数组不变。
      第一个参数为起始位置（从0开始），第二个参数为终止位置（但该位置的元素本身不包括在内）。可以负数。
      如果省略第二个参数，则一直返回到原数组的最后一个成员。
      slice方法的一个重要应用，是将类似数组的对象转为真正的数组。
    8）splice() 删除原数组的一部分成员，并可以在删除的位置添加新的数组成员，返回值是被删除的元素。改变原数组。
      第一个参数是删除的起始位置（从0开始），第二个参数是被删除的元素个数。
      如果后面还有更多的参数，则表示这些就是要被插入数组的新元素。
      如果只是单纯地插入元素，splice方法的第二个参数可以设为0。
      如果只提供第一个参数，等同于将原数组在指定位置拆分成两个数组。
    9）sort() 对数组成员进行排序，默认是按照字典顺序排序。排序后，原数组将被改变。
      数值会被先转成字符串，再按照字典顺序进行比较，所以101排在11的前面。
      如果想让sort方法按照自定义方式排序，可以传入一个函数作为参数。
        参数函数本身接受两个参数，表示进行比较的两个数组成员。
        如果该函数的返回值大于0，表示第一个成员排在第二个成员后面；其他情况下，都是第一个元素排在第二个元素前面。
        注意，自定义的排序函数应该返回数值，否则不同的浏览器可能有不同的实现
    10）map() 将数组的所有成员依次传入参数函数，然后把每一次的执行结果组成一个新数组返回。原数组没有变化。
      map方法接受一个函数作为参数，map方法向回调函数传入三个参数：当前成员、当前位置和数组本身。
      map方法还可以接受第二个参数，用来绑定回调函数内部的this变量。
      map方法不会跳过undefined和null，但是会跳过空位。
    11）forEach()
      forEach方法与map方法很相似，也是对数组的所有成员依次执行参数函数。
      forEach方法不返回值，只用来操作数据。
      如果数组遍历的目的是为了得到返回值，那么使用map方法，否则使用forEach方法。
      forEach方法也可以接受第二个参数，绑定参数函数的this变量。
      forEach方法无法中断执行，总是会将所有成员遍历完。
      forEach方法不会跳过undefined和null，但会跳过空位。
    12）filter() 用于过滤数组成员，满足条件的成员组成一个新数组返回。
      参数是一个函数，所有数组成员依次执行该函数，返回结果为true的成员组成一个新数组返回。不会改变原数组。
      参数函数可以接受三个参数：当前成员，当前位置和整个数组。
      filter方法还可以接受第二个参数，用来绑定参数函数内部的this变量。
    13）some()，every() 类似“断言”（assert），返回一个布尔值，表示判断数组成员是否符合某种条件。
      接受一个函数作为参数，所有数组成员依次执行该函数。
      该参数函数接受三个参数：当前成员、当前位置和整个数组，然后返回一个布尔值。
      some方法是只要一个成员的返回值是true，则整个some方法的返回值就是true，否则返回false。存在。
      every方法是所有成员的返回值都是true，整个every方法才返回true，否则返回false。任意。
      对于空数组，some方法返回false，every方法返回true，回调函数都不会执行。
      some和every方法还可以接受第二个参数，用来绑定参数函数内部的this变量。
    14）reduce()，reduceRight() reduce方法和reduceRight方法依次处理数组的每个成员，最终累计为一个值。
      reduce是从左到右处理（从第一个成员到最后一个成员）
      reduceRight则是从右到左（从最后一个成员到第一个成员），其他完全一样。
      第一个参数都是一个函数。
        四个参数：累积变量，默认为数组的第一个成员、当前变量，默认为数组的第二个成员、当前位置（从0开始）、原数组
        前两个是必须的，后两个则是可选的。
      如果要对累积变量指定初值，可以把它放在reduce方法和reduceRight方法的第二个参数。
      实际上还可以用来做一些遍历相关的操作。比如，找出字符长度最长的数组成员。
    15）indexOf()，lastIndexOf() 
      indexOf方法返回给定元素在数组中第一次出现的位置，如果没有出现则返回-1。
      lastIndexOf方法返回给定元素在数组中最后一次出现的位置，如果没有出现则返回-1。
    16）链式使用 上面这些数组方法之中，有不少返回的还是数组，所以可以链式使用。
</pre>
      </div>

      <!-- js标准库：包装对象 -->
      <div class="chapter" id='kp18'>
        <h2>kp18 js标准库：包装对象</h2>
        <pre>
  1、三种原始类型的值——数值、字符串、布尔值——在一定条件下，也会自动转为对象，也就是原始类型的“包装对象”（wrapper）。
    指的是与数值、字符串、布尔值分别相对应的Number、String、Boolean三个原生对象。
    包装对象的设计目的，首先是使得“对象”这种类型可以覆盖 JavaScript 所有的值，整门语言有一个通用的数据模型，
      其次是使得原始类型的值也有办法调用自己的方法。
    2、某些场合，原始类型的值会自动当作包装对象调用，即调用包装对象的属性和方法。
      这时，JavaScript 引擎会自动将原始类型的值转为包装对象实例，并在使用后立刻销毁实例。
    3、除了原生的实例方法，包装对象还可以自定义方法和属性，供原始类型的值直接调用。
    4、Boolean对象除了可以作为构造函数，还可以单独使用，将任意值转为布尔值。
      使用双重的否运算符（!）也可以将任意值转为对应的布尔值。
    5、Number对象拥有以下一些静态属性
      Number.POSITIVE_INFINITY：正的无限，指向Infinity。
      Number.NEGATIVE_INFINITY：负的无限，指向-Infinity。
      Number.NaN：表示非数值，指向NaN。
      Number.MIN_VALUE：表示最小的正数（即最接近0的正数，在64位浮点数体系中为5e-324），
        相应的，最接近0的负数为-Number.MIN_VALUE。
      Number.MAX_SAFE_INTEGER：表示能够精确表示的最大整数，即9007199254740991。
      Number.MIN_SAFE_INTEGER：表示能够精确表示的最小整数，即-9007199254740991。
    6、Number对象实例方法
      ·Number.prototype.toString()：将一个数值转为字符串形式。
        toString方法可以接受一个参数，表示输出的进制。
        只要能够让 JavaScript 引擎不混淆小数点和对象的点运算符，各种写法都能用。
        可以直接对一个小数使用toString方法。
        通过方括号运算符也可以调用toString方法。
        toString方法只能将十进制的数，转为其他进制的字符串。
        如果要将其他进制的数，转回十进制，需要使用parseInt方法。
      ·Number.prototype.toFixed()：先将一个数转为指定位数的小数，然后返回这个小数对应的字符串。
        由于浮点数的原因，小数5的四舍五入是不确定的，使用的时候必须小心。
      ·Number.prototype.toExponential()：将一个数转为科学计数法形式。
      ·Number.prototype.toPrecision()：将一个数转为指定位数的有效数字。范围是1到21
        用于四舍五入时不太可靠，跟浮点数不是精确储存有关。
      ·Number.prototype.toLocaleString()：接受一个地区码作为参数，返回一个字符串，表示当前数字在该地区的当地书写形式。
    7、字符串对象是一个类似数组的对象（很像数组，但不是数组）。
    8、String对象静态方法：
      ·String.fromCharCode()：参数是一个或多个数值，代表 Unicode 码点，返回值是这些码点组成的字符串。
    9、String对象实例方法：
      ·String.prototype.length：字符串实例的length属性返回字符串的长度。
      ·String.prototype.charAt()：charAt方法返回指定位置的字符，参数是从0开始编号的位置。
      ·String.prototype.charCodeAt()：返回字符串指定位置的 Unicode 码点（十进制表示）
        相当于String.fromCharCode()的逆操作。
      ·String.prototype.concat()：用于连接两个字符串，返回一个新字符串，不改变原字符串。
        可以接受多个参数。
        如果参数不是字符串，concat方法会将其先转为字符串，然后再连接。
      ·String.prototype.slice()：slice方法用于从原字符串取出子字符串并返回，不改变原字符串。
        第一个参数是子字符串的开始位置，第二个参数是子字符串的结束位置（不含该位置）。
      ·String.prototype.substring()：用于从原字符串取出子字符串并返回，不改变原字符串，跟slice方法很相像。
        它的第一个参数表示子字符串的开始位置，第二个位置表示结束位置（返回结果不含该位置）。
        有些规则违反直觉，因此不建议使用substring方法，应该优先使用slice。
      ·String.prototype.substr()：用于从原字符串取出子字符串并返回，不改变原字符串，跟slice和substring方法的作用相同。
      ·String.prototype.indexOf()，String.prototype.lastIndexOf()
      ·String.prototype.trim()：用于去除字符串两端的空格，返回一个新字符串，不改变原字符串。
        不仅是空格，还包括制表符（\t、\v）、换行符（\n）和回车符（\r）。
      ·String.prototype.toLowerCase()，String.prototype.toUpperCase()
        都返回一个新字符串，不改变原字符串。
      ·String.prototype.match()：用于确定原字符串是否匹配某个子字符串，返回一个数组，成员为匹配的第一个字符串。
        如果没有找到匹配，则返回null。
        返回的数组还有index属性和input属性，分别表示匹配字符串开始的位置和原始字符串
      ·String.prototype.search()，String.prototype.replace()
        search方法的用法基本等同于match，但是返回值为匹配的第一个位置。如果没有找到匹配，则返回-1。
        replace方法用于替换匹配的子字符串，一般情况下只替换第一个匹配
      ·String.prototype.split()：按照给定规则分割字符串，返回一个由分割出来的子字符串组成的数组。
        如果两个分割符中间没有其他字符，则返回数组之中会有一个空字符串。
        如果满足分割规则的部分处于字符串的开头或结尾，则返回数组的第一个或最后一个成员是一个空字符串。
        split方法还可以接受第二个参数，限定返回数组的最大成员数。
      ·String.prototype.localeCompare()：用于比较两个字符串。
        返回一个整数，如果小于0，表示第一个字符串小于第二个字符串；
        如果等于0，表示两者相等；
        如果大于0，表示第一个字符串大于第二个字符串。
</pre>
      </div>

      <!-- js标准库：Math对象 -->
      <div class="chapter" id='kp19'>
        <h2>kp19 js标准库：Math对象</h2>
        <pre>
  1、Math是 JavaScript 的原生对象，提供各种数学功能。
    该对象不是构造函数，不能生成实例，所有的属性和方法都必须在Math对象上调用。
  2、静态属性
    Math.E：常数e。
    Math.LN2：2 的自然对数。
    Math.LN10：10 的自然对数。
    Math.LOG2E：以 2 为底的e的对数。
    Math.LOG10E：以 10 为底的e的对数。
    Math.PI：常数π。
    Math.SQRT1_2：0.5 的平方根。
    Math.SQRT2：2 的平方根。
  3、静态方法  
    Math.abs()：绝对值
    Math.ceil()：向上取整：返回大于参数值的最小整数（天花板值）。
    Math.floor()：向下取整：返回小于参数值的最大整数（地板值）。
    Math.max()：最大值：返回参数之中最大的那个值
    Math.min()：最小值：返回参数之中最小的那个值
    Math.pow()：指数运算：返回以第一个参数为底数、第二个参数为幂的指数值。
    Math.sqrt()：平方根：返回参数值的平方根。如果参数是一个负值，则返回NaN。
    Math.log()：自然对数：方法返回以e为底的自然对数值。
      要计算以10为底的对数，可以先用Math.log求出自然对数，然后除以Math.LN10；
      求以2为底的对数，可以除以Math.LN2。
    Math.exp()：e的指数：返回常数e的参数次方。
    Math.round()：四舍五入
    Math.random()：随机数：返回0到1之间的一个伪随机数，可能等于0，但是一定小于1。
    Math.sin()：返回参数的正弦（参数为弧度值）
    Math.cos()：返回参数的余弦（参数为弧度值）
    Math.tan()：返回参数的正切（参数为弧度值）
    Math.asin()：返回参数的反正弦（返回值为弧度值）
    Math.acos()：返回参数的反余弦（返回值为弧度值）
    Math.atan()：返回参数的反正切（返回值为弧度值）
</pre>
      </div>

      <!-- js标准库：Date对象 -->
      <div class="chapter" id='kp20'>
        <h2>kp20 js标准库：Date对象</h2>
        <pre>
  1、Date对象可以作为普通函数直接调用，返回一个代表当前时间的字符串。
    无论有没有参数，直接调用Date总是返回当前时间。
  2、Date还可以当作构造函数使用。
    对它使用new命令，会返回一个Date对象的实例。如果不加参数，实例代表的就是当前时间。
    作为构造函数时，Date对象可以接受多种格式的参数，返回一个该参数对应的时间实例。
  3、类型自动转换时，Date实例如果转为数值，则等于对应的毫秒数；如果转为字符串，则等于对应的日期字符串。
  4、静态方法
    ·Date.now()：返回当前时间距离时间零点（1970年1月1日 00:00:00 UTC）的毫秒数，相当于Unix时间戳乘以1000。
    ·Date.parse()：解析日期字符串，返回该时间距离时间零点的毫秒数。
    ·Date.UTC()：接受年、月、日等变量作为参数，返回该时间距离时间零点的毫秒数。
  5、实例方法：Date的实例对象，有几十个自己的方法
</pre>
      </div>

      <!-- js标准库：RegExp对象 -->
      <div class="chapter" id='kp21'>
        <h2>kp21 js标准库：RegExp对象</h2>
        <pre>
  1、RegExp对象提供正则表达式的功能。
  2、正则表达式（regular expression）是一种表达文本模式（即字符串结构）的方法
    有点像字符串的模板，常常用来按照“给定模式”匹配文本。
    JavaScript 的正则表达式体系是参照 Perl 5 建立的。
  3、新建正则表达式有两种方法。一种是使用字面量，以斜杠表示开始和结束。var regex = /xyz/;
    另一种是使用RegExp构造函数。var regex = new RegExp('xyz');
    第一种方法在引擎编译代码时，就会新建正则表达式，第二种方法在运行时新建正则表达式，所以前者的效率较高。
    而且，前者比较便利和直观，所以实际应用中，基本上都采用字面量定义正则表达式。
  4、实例属性
    修饰符相关：
      ·RegExp.prototype.ignoreCase：返回一个布尔值，表示是否设置了i修饰符。
      ·RegExp.prototype.global：返回一个布尔值，表示是否设置了g修饰符。
      ·RegExp.prototype.multiline：返回一个布尔值，表示是否设置了m修饰符。
      ·RegExp.prototype.flags：返回一个字符串，包含了已经设置的所有修饰符，按字母排序。
      上面四个属性都是只读的。
    修饰符无关：
      ·RegExp.prototype.lastIndex：返回一个整数，表示下一次开始搜索的位置。
        该属性可读写，但是只在进行连续搜索时有意义。
      ·RegExp.prototype.source：返回正则表达式的字符串形式（不包括反斜杠），该属性只读。
  5、实例方法
    ·RegExp.prototype.test()：返回一个布尔值，表示当前模式是否能匹配参数字符串。
      如果正则表达式带有g修饰符，则每一次test方法都从上一次结束的位置开始向后匹配。
      带有g修饰符时，可以通过正则对象的lastIndex属性指定开始搜索的位置。
      如果正则模式是一个空字符串，则匹配所有字符串。
    ·RegExp.prototype.exec()：用来返回匹配结果。
      如果发现匹配，就返回一个数组，成员是匹配成功的子字符串，否则返回null。
      如果正则表示式包含圆括号（即含有“组匹配”），则返回的数组会包括多个成员。
        第一个成员是整个匹配成功的结果，后面的成员就是圆括号对应的匹配成功的组。
      exec()方法的返回数组还包含以下两个属性：
        input：整个原字符串。
        index：模式匹配成功的开始位置（从0开始计数）。
  6、字符串的实例方法之中，有4种与正则表达式有关。（参数都可以是正则）
    String.prototype.match()：返回一个数组，成员是所有匹配的子字符串。
    String.prototype.search()：按照给定的正则表达式进行搜索，返回一个整数，表示匹配开始的位置。
    String.prototype.replace()：按照给定的正则表达式进行替换，返回替换后的字符串。
    String.prototype.split()：按照给定规则进行字符串分割，返回一个数组，包含分割后的各个成员。
  7、匹配规则
    1）字面量字符和元字符
      某个字符只表示它字面的含义，就叫做“字面量字符”（literal characters）。
      一部分字符有特殊含义，不代表字面的意思。它们叫做“元字符”（metacharacters）
        ·点字符（.）匹配除回车（\r）、换行(\n) 、行分隔符（\u2028）和段分隔符（\u2029）以外的所有字符。
        ·位置字符提示字符所处的位置：^ 表示字符串的开始位置；$ 表示字符串的结束位置
        ·选择符（|）在正则表达式中表示“或关系”（OR），多个选择符可以联合使用。
        ·转义符\
          如果使用RegExp方法生成正则对象，转义需要使用两个斜杠，因为字符串内部会先转义一次。
        ·字符类（class）表示有一系列字符可供选择，只要匹配其中一个就可以了，[]
          脱字符（^）：如果方括号内的第一个字符是[^]，表示除了字符类之中的字符，其他字符都可以匹配
            如果方括号内没有其他字符，即只有[^]，就表示匹配一切字符，其中包括换行符，点号作为元字符（.）是不包括换行符的。
            脱字符只有在字符类的第一个位置才有特殊含义，否则就是字面含义。
          连字符（-）：某些情况下，对于连续序列的字符，连字符（-）用来提供简写形式，表示字符的连续范围
            字符类[1-31]，不代表1到31，只代表1到3。
    2）预定义模式指的是某些常见模式的简写方式。
      \d 匹配0-9之间的任一数字，相当于[0-9]。
      \D 匹配所有0-9以外的字符，相当于[^0-9]。
      \w 匹配任意的字母、数字和下划线，相当于[A-Za-z0-9_]。
      \W 除所有字母、数字和下划线以外的字符，相当于[^A-Za-z0-9_]。
      \s 匹配空格（包括换行符、制表符、空格符等），相等于[ \t\r\n\v\f]。
      \S 匹配非空格的字符，相当于[^ \t\r\n\v\f]。
      \b 匹配词的边界。
      \B 匹配非词边界，即在词的内部。
    3）重复类：模式的精确匹配次数，使用大括号（{}）表示。
      {n}表示恰好重复n次，{n,}表示至少重复n次，{n,m}表示重复不少于n次，不多于m次。
    4）量词符：量词符用来设定某个模式出现的次数。
      ? 问号表示某个模式出现0次或1次，等同于{0, 1}。
      * 星号表示某个模式出现0次或多次，等同于{0,}。
      + 加号表示某个模式出现1次或多次，等同于{1,}。
    5）贪婪模式
      三个量词符，默认情况下都是最大可能匹配，即匹配直到下一个字符不满足匹配规则为止。这被称为贪婪模式。
      如果想将贪婪模式改为非贪婪模式，可以在量词符后面加一个问号。
      非贪婪模式，一旦条件满足，就不再往下匹配。
    6）修饰符：修饰符（modifier）表示模式的附加规则，放在正则模式的最尾部。
      修饰符可以单个使用，也可以多个一起使用。
      ·g修饰符表示全局匹配（global），加上它以后，正则对象将匹配全部符合条件的结果，主要用于搜索和替换。
        每次都是从上一次匹配成功处，开始向后匹配。
      ·i修饰符表示忽略大小写（ignoreCase）。
      ·m修饰符表示多行模式（multiline），会修改^和$的行为。
        默认情况下（即不加m修饰符时），^和$匹配字符串的开始处和结尾处，
        加上m修饰符以后，^和$还会匹配行首和行尾，即^和$会识别换行符（\n）。
    7）组匹配：正则表达式的括号表示分组匹配，括号中的模式可以用来匹配分组的内容。
      注意，使用组匹配时，不宜同时使用g修饰符，否则match方法不会捕获分组的内容。
    8）(?:x)称为非捕获组（Non-capturing group），表示不返回该组匹配的内容，即匹配的结果中不计入这个括号。
</pre>
      </div>

      <!-- js标准库：JSON对象 -->
      <div class="chapter" id='kp22'>
        <h2>kp22 js标准库：JSON对象</h2>
        <pre>
  1、JSON 格式（JavaScript Object Notation 的缩写）是一种用于数据交换的文本格式
    JSON 对值的类型和格式有严格的规定。
      复合类型的值只能是数组或对象，不能是函数、正则表达式对象、日期对象。
      原始类型的值只有四种：字符串、数值（必须以十进制表示）、布尔值和null。
      字符串必须使用双引号表示，不能使用单引号。
      对象的键名必须放在双引号里面。
      数组或对象最后一个成员的后面，不能加逗号。
      【注意，null、空数组和空对象都是合法的 JSON 值。】
  2、JSON对象是 JavaScript 的原生对象，用来处理 JSON 格式数据。
  3、静态方法：JSON.stringify()和JSON.parse()。
    JSON.stringify方法用于将一个值转为 JSON 字符串。
      如果对象的属性是undefined、函数或 XML 对象，该属性会被JSON.stringify过滤。
      如果数组的成员是undefined、函数或 XML 对象，则这些值被转成null。
      JSON.stringify方法会忽略对象的不可遍历的属性。
      JSON.stringify方法还可以接受一个数组作为第二个参数，指定需要转成字符串的属性。
      第二个参数还可以是一个函数，用来更改JSON.stringify的返回值。注意，这个处理函数是递归处理所有的键。
      JSON.stringify还可以接受第三个参数，用于增加返回的 JSON 字符串的可读性。
        如果是数字，表示每个属性前面添加的空格（最多不超过10个）；
        如果是字符串（不超过10个字符），则该字符串会添加在每行前面。
      如果参数对象有自定义的toJSON方法，那么JSON.stringify会使用这个方法的返回值作为参数，而忽略原对象的其他属性。
    JSON.parse()：将 JSON 字符串转换成对应的值。
      如果传入的字符串不是有效的 JSON 格式，JSON.parse方法将报错。
      可以接受一个处理函数，作为第二个参数，用法与JSON.stringify方法类似。
</pre>
      </div>

      <!-- 实例对象与new命令 -->
      <div class="chapter" id='kp23'>
        <h2>kp23 实例对象与new命令</h2>
        <pre>
  1、面向对象编程（Object Oriented Programming，缩写为 OOP）
    将真实世界各种复杂的关系，抽象为一个个对象，然后由对象之间的分工与合作，完成对真实世界的模拟。
    两个层次：
      1）对象是单个实物的抽象。
      2）对象是一个容器，封装了属性（property）和方法（method）。
  2、JavaScript 语言的对象体系，不是基于“类”的，而是基于构造函数（constructor）和原型链（prototype）。
    JavaScript 语言使用构造函数（constructor）作为对象的模板。
    构造函数的特点有两个。
      函数体内部使用了this关键字，代表了所要生成的对象实例。
      生成对象的时候，必须使用new命令。
  3、new命令的作用，就是执行构造函数，返回一个实例对象。
    根据需要，构造函数也可以接受参数。
    如果忘了使用new命令，构造函数就变成了普通函数，并不会生成实例对象。
      而且this这时代表全局对象，将造成一些意想不到的结果。
      解决：
        ·构造函数内部使用严格模式，即第一行加上use strict。
        ·构造函数内部判断是否使用new命令，如果发现没有使用，则直接返回一个实例对象。
          this instanceof Fubar
  4、使用new命令时，它后面的函数依次执行下面的步骤：
    ·创建一个空对象，作为将要返回的对象实例。
    ·将这个空对象的原型，指向构造函数的prototype属性。
    ·将这个空对象赋值给函数内部的this关键字。
    ·开始执行构造函数内部的代码。
    构造函数内部，this指的是一个新生成的空对象，所有针对this的操作，都会发生在这个空对象上。
    之所以叫“构造函数”，就是说这个函数的目的，就是操作一个空对象（即this对象），将其“构造”为需要的样子。
    如果构造函数内部有return语句，而且return后面跟着一个对象，new命令会返回return语句指定的对象；
      否则，就会不管return语句，返回this对象。
    如果对普通函数（内部没有this关键字的函数）使用new命令，则会返回一个空对象。
    new.target属性。如果当前函数是new命令调用，new.target指向当前函数，否则为undefined。
      可以判断函数调用的时候，是否使用new命令。
  5、Object.create() 创建实例对象
    以现有的对象作为模板，生成新的实例对象，这时就可以使用Object.create()方法。
</pre>
      </div>

      <!-- this关键字 -->
      <div class="chapter" id='kp24'>
        <h2>kp24 this关键字</h2>
        <pre>
  1、简单说，this就是属性或方法“当前”所在的对象。
    由于对象的属性/方法可以赋给另一个对象，所以属性所在的当前对象是可变的，即this的指向是可变的。
    JavaScript 语言之中，一切皆对象，运行环境也是对象，
      所以函数都是在某个对象之中运行，this就是函数运行时所在的对象（环境）
    JavaScript 支持运行环境动态切换，也就是说，this的指向是动态的，没有办法事先确定到底指向哪个对象
  2、JavaScript 语言之所以有 this 的设计，跟内存里面的数据结构有关系。
    属性的值可能是一个函数。引擎会将函数单独保存在内存中，然后再将函数的地址赋值给foo属性的value属性。
    由于函数是一个单独的值，所以它可以在不同的环境（上下文）执行。
    JavaScript 允许在函数体内部，引用当前环境的其他变量。（闭包）
    this的设计目的就是在函数体内部，指代函数当前的运行环境。
  3、使用场合
    1）全局环境使用this，它指的就是顶层对象window。
    2）构造函数中的this，指的是实例对象。
    3）如果对象的方法里面包含this，this的指向就是方法运行时所在的对象。
      该方法赋值给另一个对象，就会改变this的指向。
      下面这几种用法，都会改变this的指向。
        (obj.foo = obj.foo)() // window
        (false || obj.foo)() // window
        (1, obj.foo)() // window
      上面代码中，obj.foo就是一个值，真正调用的时候，运行环境不是obj，而是全局环境，this不再指向obj。
  4、由于this的指向是不确定的，所以切勿在函数中包含多层的this。
    使用一个变量固定this的值，然后内层函数调用这个变量，是非常常见的做法
    严格模式下，如果函数内部的this指向顶层对象，就会报错。
  5、数组的map和foreach方法，允许提供一个函数作为参数。这个函数内部不应该使用this
    解决：
      使用中间变量固定this。
      将this当作foreach方法的第二个参数，固定它的运行环境。
  6、回调函数中的this往往会改变指向，最好避免使用。
  7、绑定 this 的方法
    1）Function.prototype.call()
      函数实例的call方法，可以指定函数内部this的指向（即函数执行时所在的作用域），
        然后在所指定的作用域中，调用该函数。
      call方法实质上是调用Function.prototype.call方法
      call方法的参数，应该是一个对象。如果参数为空、null和undefined，则默认传入全局对象。
      如果call方法的参数是一个原始值，那么这个原始值会自动转成对应的包装对象，然后传入call方法。
      call方法还可以接受多个参数。第一个参数就是this所要指向的那个对象，后面的参数则是函数调用时所需的参数。
    2）Function.prototype.apply()
      apply方法的作用与call方法类似，也是改变this指向，然后再调用该函数。
      区别是，它接收一个数组作为函数执行时的参数，
      利用数组对象的slice方法，可以将一个类似数组的对象（比如arguments对象）转为真正的数组。
        Array.prototype.slice.apply(ArrayLikeObj)
      apply方法（或者call方法）不仅绑定函数执行时所在的对象，还会立即执行函数
    3）Function.prototype.bind()
      bind方法用于将函数体内的this绑定到某个对象，然后返回一个新函数。
      bind方法的参数就是所要绑定this的对象
      bind还可以接受更多的参数，将这些参数绑定原函数的参数。
      如果bind方法的第一个参数是null或undefined，等于将this绑定到全局对象，函数运行时this指向顶层对象（浏览器为window）。
      注意：
        bind方法每运行一次，就返回一个新函数
        回调函数是 JavaScript 最常用的模式之一，但错误是，将包含this的方法直接当作回调函数。解决方法就是使用bind方法
        某些数组方法可以接受一个函数当作参数。这些函数内部的this指向，很可能也会出错。
</pre>
      </div>

      <!-- 对象的继承 -->
      <div class="chapter" id='kp25'>
        <h2>kp25 对象的继承</h2>
        <pre>
  1、传统上，JavaScript 语言的继承不通过 class，而是通过“原型对象”（prototype）实现
  2、通过构造函数为实例对象定义属性，虽然很方便，但是有一个缺点。
    同一个构造函数的多个实例之间，无法共享属性，从而造成对系统资源的浪费。
    这个问题的解决方法，就是 JavaScript 的原型对象（prototype）
  3、JavaScript 继承机制的设计思想就是，原型对象的所有属性和方法，都能被实例对象共享。
    如果属性和方法定义在原型上，那么所有实例对象就能共享，不仅节省了内存，还体现了实例对象之间的联系。
  4、函数默认具有prototype属性，指向一个对象。
    对于构造函数来说，生成实例的时候，该属性会自动成为实例对象的原型。
    原型对象的属性不是实例对象自身的属性。只要修改原型对象，变动就立刻会体现在所有实例对象上。
    当实例对象本身没有某个属性或方法的时候，它会到原型对象去寻找该属性或方法。
    原型对象的作用，就是定义所有实例对象共享的属性和方法。
    实例对象可以视作从原型对象衍生出来的子对象。
  5、JavaScript 规定，所有对象都有自己的原型对象（prototype）。
    一方面，任何一个对象，都可以充当其他对象的原型；
    另一方面，由于原型对象也是对象，所以它也有自己的原型。
    因此，就会形成一个“原型链”（prototype chain）
    所有对象的原型最终都可以上溯到Object.prototype，即Object构造函数的prototype属性。
    Object.prototype对象是null。null没有任何属性和方法，也没有自己的原型。因此，原型链的尽头就是null。
    如果对象自身和它的原型，都定义了一个同名属性，那么优先读取对象自身的属性，这叫做“覆盖”（overriding）。
    注意，一级级向上，在整个原型链上寻找某个属性，对性能是有影响的。
  6、prototype对象有一个constructor属性，默认指向prototype对象所在的构造函数。
    constructor属性定义在prototype对象上面，意味着可以被所有实例对象继承。
    作用是，可以得知某个实例对象，到底是哪一个构造函数产生的。
    有了constructor属性，就可以从一个实例对象新建另一个实例。
    constructor属性表示原型对象与构造函数之间的关联关系
      如果修改了原型对象，一般会同时修改constructor属性，防止引用的时候出错。
    要么将constructor属性重新指向原来的构造函数，要么只在原型对象上添加方法，这样可以保证instanceof运算符不会失真。
    如果不能确定constructor属性是什么函数，还有一个办法：通过name属性，从实例得到构造函数的名称。
  7、instanceof运算符返回一个布尔值，表示对象是否为某个构造函数的实例。
    左边是实例对象，右边是构造函数。它会检查右边构建函数的原型对象（prototype），是否在左边对象的原型链上。
    由于instanceof检查整个原型链，因此同一个实例对象，可能会对多个构造函数都返回true。
    除了null，其他对象的instanceOf Object的运算结果都是true。
    instanceof运算符只能用于对象，不适用原始类型的值。
    利用instanceof运算符，还可以巧妙地解决，调用构造函数时，忘了加new命令的问题。
  8、构造函数的继承
    第一步，在子类的构造函数中，调用父类的构造函数。
      function Sub(value) { Super.call(this); this.prop = value; }
      call方法改变Super构造函数内部this的指向，传入Sub构造函数的上下文
    第二步，让子类的原型指向父类的原型，这样子类就可以继承父类原型。
      Sub.prototype = Object.create(Super.prototype);
      Sub.prototype.constructor = Sub;
  9、多重继承
    JavaScript不提供多重继承功能，即不允许一个对象同时继承多个对象。
    但是，可以通过变通方法，实现这个功能。
    S.prototype = Object.create(M1.prototype);// 继承 M1
    Object.assign(S.prototype, M2.prototype);// 继承链上加入 M2
    子类S同时继承了父类M1和M2。这种模式又称为 Mixin（混入）。
  10、传统做法，如何利用对象实现模块的效果。
    “立即执行函数”（Immediately-Invoked Function Expression，IIFE）
    “放大模式”（augmentation）
    "宽放大模式"（Loose augmentation）
</pre>
      </div>

      <!-- Object对象的相关方法 -->
      <div class="chapter" id='kp26'>
        <h2>kp26 Object对象的相关方法</h2>
        <pre>
  1、Object.getPrototypeOf方法返回参数对象的原型。这是获取原型对象的标准方法。
  2、Object.setPrototypeOf方法为参数对象设置原型，返回该参数对象。
    两个参数，第一个是现有对象，第二个是原型对象。
  3、Object.create()：接受一个对象作为参数，然后以它为原型，返回一个实例对象。
    该实例完全继承原型对象的属性。
    实质是新建一个空的构造函数F，然后让F.prototype属性指向参数对象obj，最后返回一个F的实例，从而实现让该实例继承obj的属性。
    使用Object.create方法的时候，必须提供对象原型，即参数不能为空，或者不是对象，否则会报错。
    Object.create方法生成的新对象，动态继承了原型。在原型上添加或修改任何方法，会立刻反映在新对象之上。
    还可以接受第二个参数。该参数是一个属性描述对象，它所描述的对象属性，会添加到实例对象，作为该对象自身的属性。
  4、Object.prototype.isPrototypeOf()：用来判断该对象是否为参数对象的原型。
    只要实例对象处在参数对象的原型链上，isPrototypeOf方法都返回true。
  5、Object.prototype.__proto__
    实例对象的__proto__属性（前后各两个下划线），返回该对象的原型。该属性可读写。
    根据语言标准，__proto__属性只有浏览器才需要部署
    本质是一个内部属性，不应该对使用者暴露。因此，应该尽量少用这个属性
  6、获取实例对象obj的原型对象，有三种方法。
    obj.__proto__
    obj.constructor.prototype
    Object.getPrototypeOf(obj)
  7、Object.getOwnPropertyNames方法返回一个数组，成员是参数对象本身的所有属性的键名，不包含继承的属性键名。
    返回所有键名，不管是否可以遍历，只获取那些可以遍历的属性，使用Object.keys方法。
  8、Object.prototype.hasOwnProperty()：返回一个布尔值，用于判断某个属性定义在对象自身，还是定义在原型链上。
    hasOwnProperty方法是 JavaScript 之中唯一一个处理对象属性时，不会遍历原型链的方法。
  9、in运算符返回一个布尔值，表示一个对象是否具有某个属性。它不区分该属性是对象自身的属性，还是继承的属性。
    获得对象的所有可遍历属性（不管是自身的还是继承的），可以使用for...in循环。
  10、对象的拷贝：
    确保拷贝后的对象，与原对象具有同样的原型。
    确保拷贝后的对象，与原对象具有同样的实例属性。
</pre>
      </div>

      <!-- 严格模式 -->
      <div class="chapter" id='kp27'>
        <h2>kp27 严格模式</h2>
        <pre>
  严格模式是从 ES5 进入标准的，主要目的有以下几个。
    明确禁止一些不合理、不严谨的语法，减少 JavaScript 语言的一些怪异行为。
    增加更多报错的场合，消除代码运行的一些不安全之处，保证代码运行的安全。
    提高编译器效率，增加运行速度。
    为未来新版本的 JavaScript 语法做好铺垫。
</pre>
      </div>

      <!-- 异步操作概述 -->
      <div class="chapter" id='kp28'>
        <h2>kp28 异步操作概述</h2>
        <pre>
  1、单线程模型
    JavaScript 只在一个线程上运行。也就是说，JavaScript 同时只能执行一个任务
    注意，JavaScript 只在一个线程上运行，不代表 JavaScript 引擎只有一个线程。
    JavaScript 引擎有多个线程，单个脚本只能在一个线程上运行（称为主线程），其他线程都是在后台配合。
    为了利用多核 CPU 的计算能力，HTML5 提出 Web Worker 标准，允许 JavaScript 脚本创建多个线程，
      但是子线程完全受主线程控制，且不得操作 DOM。
  2、同步任务（synchronous）和异步任务（asynchronous）
    同步任务是那些没有被引擎挂起、在主线程上排队执行的任务。
    异步任务是那些被引擎放在一边，不进入主线程、而进入任务队列的任务。
  3、任务队列和事件循环
    1）JavaScript 运行时，除了一个正在运行的主线程，引擎还提供一个任务队列（task queue），
      里面是各种需要当前程序处理的异步任务。实际上，根据异步任务的类型，存在多个任务队列。
    2）首先，主线程会去执行所有的同步任务。等到同步任务全部执行完，就会去看任务队列里面的异步任务。
      如果满足条件，那么异步任务就重新进入主线程开始执行，这时它就变成同步任务了。
      等到执行完，下一个异步任务再进入主线程开始执行。
      一旦任务队列清空，程序就结束执行。
    3）异步任务的写法通常是回调函数。一旦异步任务重新进入主线程，就会执行对应的回调函数。
      如果一个异步任务没有回调函数，就不会进入任务队列，
      也就是说，不会重新进入主线程，因为没有用回调函数指定下一步的操作。
    4）引擎在不停地检查，一遍又一遍，只要同步任务执行完了，引擎就会去检查那些挂起来的异步任务，是不是可以进入主线程了。
      这种循环检查的机制，就叫做事件循环（Event Loop）。
      事件循环是一个程序结构，用于等待和发送消息和事件
  4、异步操作模式
    1）回调函数是异步操作最基本的方法。
      简单、容易理解和实现，
      不利于代码的阅读和维护，各个部分之间高度耦合（coupling），
        使得程序结构混乱、流程难以追踪（尤其是多个回调函数嵌套的情况），
      而且每个任务只能指定一个回调函数。
    2）事件监听，事件驱动模式
      异步任务的执行不取决于代码的顺序，而取决于某个事件是否发生。
      比较容易理解，可以绑定多个事件，每个事件可以指定多个回调函数，而且可以“去耦合”（decoupling），有利于实现模块化
      整个程序都要变成事件驱动型，运行流程会变得很不清晰。阅读代码的时候，很难看出主流程。
    3）发布/订阅
      事件完全可以理解成“信号”，如果存在一个“信号中心”，某个任务执行完成，就向信号中心“发布”（publish）一个信号，
        其他任务可以向信号中心“订阅”（subscribe）这个信号，从而知道什么时候自己可以开始执行。
      这就叫做”发布/订阅模式”（publish-subscribe pattern），又称“观察者模式”（observer pattern）。
      性质与“事件监听”类似，但更优。通过查看“消息中心”，了解存在多少信号、每个信号有多少订阅者，从而监控程序的运行。
  5、异步操作的流程控制
    流程控制：如何确定异步操作执行的顺序，以及如何保证遵守这种顺序。
    1）串行执行
      编写一个流程控制函数，让它来控制异步任务，一个任务完成以后，再执行另一个。这就叫串行执行。
    2）并行执行
      也可以是并行执行，即所有异步任务同时执行，等到全部完成以后，才执行final函数。
    3）并行与串行的结合
      设置一个门槛，每次最多只能并行执行n个异步任务，这样就避免了过分占用系统资源。
</pre>
      </div>

      <!-- 定时器 -->
      <div class="chapter" id='kp29'>
        <h2>kp29 定时器</h2>
        <pre>
  1、setTimeout函数用来指定某个函数或某段代码，在多少毫秒之后执行。
    返回一个整数，表示定时器的编号，以后可以用来取消这个定时器。
    第一个参数func|code是将要推迟执行的函数名或者一段代码，第二个参数delay是推迟执行的毫秒数（默认0）。
    更多的参数将依次传入推迟执行的函数（回调函数）。
    如果回调函数是对象的方法，那么setTimeout使得方法内部的this关键字指向全局环境，而不是定义时所在的那个对象。
      一种解决方法是将obj.y放入一个函数。使得obj.y在obj的作用域执行，而不是在全局作用域内执行
      一种解决方法是，使用bind方法，将obj.y这个方法绑定在obj上面。
  2、setInterval函数的用法与setTimeout完全一致
    区别在于setInterval指定某个任务每隔一段时间就执行一次，也就是无限次的定时执行。
    setInterval指定的是“开始执行”之间的间隔，并不考虑每次任务执行本身所消耗的时间
      指定每 100ms 执行一次，每次执行需要 5ms，那么第一次执行结束后95毫秒，第二次执行就会开始
      执行耗时特别长，需要105毫秒，那么它结束后，下一次执行就会立即开始。
    为确保两次执行之间有固定间隔，可以不用setInterval，而是每次执行结束后，使用setTimeout指定下一次执行的具体时间。
  3、clearTimeout()，clearInterval()：传入定时器编号，取消对应的定时器。
    setTimeout和setInterval返回的整数值是连续的
    利用这一点，可以写一个函数，取消当前所有的setTimeout定时器。
  4、实例：debounce 函数，防抖动
    有时，我们不希望回调函数被频繁调用（频繁的按键触发ajax请求），设置一个门槛值，表示两次 Ajax 通信的最小间隔时间。
  5、setTimeout和setInterval的运行机制
    将指定的代码移出本轮事件循环，等到下一轮事件循环，再检查是否到了指定时间。
    这意味着，setTimeout和setInterval指定的回调函数，必须等到本轮事件循环的所有同步任务都执行完，才会开始执行。
  6、setTimeout(f, 0)
    必须要等到当前脚本的同步任务，全部处理完以后，才会执行setTimeout指定的回调函数f
    setTimeout(f, 0)会在下一轮事件循环一开始就执行。
    应用：
      调整事件的发生顺序，如果，想让父元素的事件回调函数先发生，就要用到setTimeout(f, 0)。
      用户自定义的回调函数，通常在浏览器的默认动作之前触发，如果要在想在之后触发
    实际上意味着，将任务放到浏览器最早可得的空闲时段执行
      所以计算量大、耗时长的任务，常会被放到几个小部分，分别放到setTimeout(f, 0)里面执行。
</pre>
        <button id="debounceBtn" type="button">防抖动</button>
        <script>
          const debounceBtn = document.querySelector("#debounceBtn");
          const handleBtnClick = () => {
            debounceBtn.removeEventListener("click", handleBtnClick);
            debounceBtn.disabled = true;
            let debounceBtnTimer = setTimeout(() => {
              debounceBtn.addEventListener("click", handleBtnClick);
              debounceBtn.disabled = false;
            }, 3000);
            console.log("你点击了防抖动按钮");
            // debounceBtn.removeEventListener("click", handleBtnClick.bind(context));
            // debounceBtn.removeEventListener("click", () => handleBtnClick());
          };
          // debounceBtn.addEventListener("click", handleBtnClick.bind(this));
          debounceBtn.addEventListener("click", handleBtnClick);
          // debounceBtn.addEventListener("click", () => {
          //   console.log("点了", Date.now());
          // })
        </script>
        <input id="capText" type="text">
        <script>
          const capText = document.querySelector("#capText");
          const upperCase = (e) => {
            let self = e.target;
            setTimeout(() => {
              self.value = self.value.toUpperCase();
            }, 0);
          };
          capText.addEventListener("keypress", upperCase);
        </script>
      </div>

      <!-- Promise对象 -->
      <div class="chapter" id='kp30'>
        <h2>kp30 Promise对象</h2>
        <pre>
  1、Promise 对象是 JavaScript 的异步操作解决方案，为异步操作提供统一接口。
    起到代理作用（proxy），充当异步操作与回调函数之间的中介，使得异步操作具备同步操作的接口。
    Promise 是一个对象，也是一个构造函数
    Promise 的设计思想是，所有异步任务都返回一个 Promise 实例。
    JavaScript 原生支持 Promise 对象。
  2、Promise 对象通过自身的状态，来控制异步操作。
    异步操作未完成（pending）
    异步操作成功（fulfilled）
    异步操作失败（rejected）
    fulfilled和rejected合在一起称为resolved（已定型）
    三种的状态的变化途径只有两种：从“未完成”到“成功”、从“未完成”到“失败”
    Promise 实例的状态变化只可能发生一次。
    Promise 的最终结果只有两种：
      异步操作成功，Promise 实例传回一个值（value），状态变为fulfilled。
      异步操作失败，Promise 实例抛出一个错误（error），状态变为rejected。
  3、Promise构造函数接受一个函数作为参数，该函数的两个参数分别是resolve和reject。
    由 JavaScript 引擎提供，不用自己实现。
    ·resolve函数将Promise实例的状态从“未完成”变为“成功”（即从pending变为fulfilled），
      在异步操作成功时调用，并将异步操作的结果，作为参数传递出去。
    ·reject函数将Promise实例的状态从“未完成”变为“失败”（即从pending变为rejected），
      在异步操作失败时调用，并将异步操作报出的错误，作为参数传递出去。
  4、Promise.prototype.then()：Promise 实例的then方法，用来添加回调函数。
    接受两个回调函数，
      第一个是异步操作成功时（变为fulfilled状态）的回调函数，
      第二个是异步操作失败（变为rejected）时的回调函数（该参数可以省略）。
  5、Promise 的用法，简单说就是一句话：使用then方法添加回调函数。
  6、Promise 的回调函数不是正常的异步任务，而是微任务（microtask）。
    区别在于，正常任务追加到下一轮事件循环，微任务追加到本轮事件循环。
    微任务的执行时间一定早于正常任务。
    then是本轮事件循环执行，setTimeout(fn, 0)在下一轮事件循环开始时执行。
</pre>
      </div>

      <!-- DOM概述 -->
      <div class="chapter" id='kp31'>
        <h2>kp31 DOM概述</h2>
        <pre>
  1、DOM 是 JavaScript 操作网页的接口，全称为“文档对象模型”（Document Object Model）。
    将网页转为一个 JavaScript 对象，从而可以用脚本进行各种操作（比如增删内容）。
    浏览器根据 DOM 模型，将结构化文档（比如 HTML 和 XML）解析成一系列的节点，再由这些节点组成一个树状结构（DOM Tree）。
    所有的节点和最终的树状结构，都有规范的对外接口。
    DOM 只是一个接口规范，可以用各种语言实现。
  2、DOM 的最小组成单位叫做节点（node）
    文档的树形结构（DOM 树），就是由各种不同类型的节点组成。
    节点的类型有七种：
      Document：整个文档树的顶层节点
      DocumentType：doctype标签（比如< !DOCTYPE html>）
      Element：网页的各种HTML标签（比如< body>、< a>等）
      Attribute：网页元素的属性（比如class="right"）
      Text：标签之间或标签包含的文本
      Comment：注释
      DocumentFragment：文档的片段
    浏览器提供一个原生的节点对象Node，上面这七种节点都继承了Node，因此具有一些共同的属性和方法。
  3、DOM树：一个文档的所有节点，按照所在的层级，可以抽象成一种树状结构。
    浏览器原生提供document节点，代表整个文档。
    除了根节点，其他节点都有三种层级关系：
      父节点关系（parentNode）：直接的那个上级节点
      子节点关系（childNodes）：直接的下级节点
      同级节点关系（sibling）：拥有同一个父节点的节点
</pre>
      </div>

      <!-- Node接口 -->
      <div class="chapter" id='kp32'>
        <h2>kp32 Node接口</h2>
        <pre>
  1、属性
    1）Node.prototype.nodeType：返回一个整数值，表示节点的类型
      不同节点的nodeType属性值和对应的常量如下：
        文档节点（document）：9，对应常量Node.DOCUMENT_NODE
        元素节点（element）：1，对应常量Node.ELEMENT_NODE
        属性节点（attr）：2，对应常量Node.ATTRIBUTE_NODE
        文本节点（text）：3，对应常量Node.TEXT_NODE
        文档片断节点（DocumentFragment）：11，对应常量Node.DOCUMENT_FRAGMENT_NODE
        文档类型节点（DocumentType）：10，对应常量Node.DOCUMENT_TYPE_NODE
        注释节点（Comment）：8，对应常量Node.COMMENT_NODE
    2）Node.prototype.nodeName：返回节点的名称
      不同节点的nodeName属性值如下：
        文档节点（document）：#document
        元素节点（element）：大写的标签名
        属性节点（attr）：属性的名称
        文本节点（text）：#text
        文档片断节点（DocumentFragment）：#document-fragment
        文档类型节点（DocumentType）：文档的类型
        注释节点（Comment）：#comment
    3）Node.prototype.nodeValue：返回一个字符串，表示当前节点本身的文本值，该属性可读写
      只有文本节点（text）、注释节点（comment）和属性节点（attr）有文本值
    4）Node.prototype.textContent：返回当前节点和它的所有后代节点的文本内容
      textContent属性自动忽略当前节点内部的 HTML 标签，返回所有文本内容
      该属性是可读写的，设置该属性的值，会用一个新的文本节点，替换所有原来的子节点。
      它还有一个好处，就是自动对 HTML 标签转义。这很适合用于用户提供的内容。将< p>标签解释为文本，而不会当作标签处理。
    5）Node.prototype.baseURI：返回一个字符串，表示当前网页的绝对路径。
      浏览器根据这个属性，计算网页上的相对路径的 URL。该属性为只读。
    6）Node.prototype.ownerDocument：返回当前节点所在的顶层文档对象，即document对象。
    7）Node.prototype.nextSibling：返回紧跟在当前节点后面的第一个同级节点。
      如果当前节点后面没有同级节点，则返回null。
    8）Node.prototype.previousSibling：返回当前节点前面的、距离最近的一个同级节点。
      如果当前节点前面没有同级节点，则返回null。
    9）Node.prototype.parentNode：返回当前节点的父节点
      父节点只可能是三种类型：元素节点（element）、文档节点（document）和文档片段节点（documentfragment）。
      文档节点（document）和文档片段节点（documentfragment）的父节点都是null。
      对于那些生成后还没插入 DOM 树的节点，父节点也是null。
    10）Node.prototype.parentElement：返回当前节点的父元素节点
      如果当前节点没有父节点，或者父节点类型不是元素节点，则返回null。
      父节点只可能是三种类型：元素节点、文档节点和文档片段节点。parentElement属性相当于把后两种父节点都排除了。
    11）Node.prototype.firstChild，Node.prototype.lastChild
      firstChild属性返回当前节点的第一个子节点，如果当前节点没有子节点，则返回null。
        注意，firstChild返回的除了元素节点，还可能是文本节点或注释节点。
        p元素与span元素之间有空白字符，这导致firstChild返回的是文本节点。
      lastChild属性返回当前节点的最后一个子节点，如果当前节点没有子节点，则返回null。用法与firstChild属性相同。
    12）Node.prototype.childNodes：返回一个类似数组的对象（NodeList集合），成员包括当前节点的所有子节点。
      文档节点（document）就有两个子节点：文档类型节点（docType）和 HTML 根元素节点。
      注意，除了元素节点，childNodes属性的返回值还包括文本节点和注释节点。
      NodeList对象是一个动态集合，一旦子节点发生变化，立刻会反映在返回结果之中。
    13）Node.prototype.isConnected：返回一个布尔值，表示当前节点是否在文档之中。
      生成的节点，没有插入文档之前，isConnected属性返回false，插入之后返回true。
  2、方法：
    1）Node.prototype.appendChild()：接受一个节点对象作为参数，将其作为最后一个子节点，插入当前节点。
      如果参数节点是 DOM 已经存在的节点，appendChild()方法会将其从原来的位置，移动到新位置。
      如果参数是DocumentFragment节点，那么插入DocumentFragment的所有子节点，而非DocumentFragment节点本身。
    2）Node.prototype.hasChildNodes()：返回一个布尔值，表示当前节点是否有子节点。
      注意，子节点包括所有类型的节点，并不仅仅是元素节点。哪怕节点只包含一个空格，hasChildNodes方法也会返回true。
    3）Node.prototype.cloneNode()：克隆一个节点。
      它接受一个布尔值作为参数，表示是否同时克隆子节点。它的返回值是一个克隆出来的新节点。
    4）Node.prototype.insertBefore()：将某个节点插入父节点内部的指定位置。
      第一个参数是所要插入的节点newNode，第二个参数是父节点parentNode内部的一个子节点referenceNode
      第二个参数为null，则新节点将插在当前节点内部的最后位置，成最后一个子节点。
      注意，如果所要插入的节点是当前 DOM 现有的节点，则该节点将从原有的位置移除，插入新的位置。
      如果新节点要插在父节点的某个子节点后面，parent.insertBefore(s1, s2.nextSibling);
      如果要插入的节点是DocumentFragment类型，那么插入的将是DocumentFragment的所有子节点，
        而不是DocumentFragment节点本身。返回值将是一个空的DocumentFragment节点。
    5）Node.prototype.removeChild()：接受一个子节点作为参数，用于从当前节点移除该子节点。返回值是移除的子节点。
      被移除的节点依然存在于内存之中，但不再是 DOM 的一部分。
    6）Node.prototype.replaceChild()：用于将一个新的节点，替换当前节点的某一个子节点。
      第一个参数newChild是用来替换的新节点，第二个参数oldChild是将要替换走的子节点。
      返回值是替换走的那个节点oldChild。
    7）Node.prototype.contains()：返回一个布尔值，参数节点是否是当前节点或当前节点的后代节点
    8）Node.prototype.compareDocumentPosition()：与contains方法完全一致
      返回一个六个比特位的二进制值，表示参数节点与当前节点的关系。
    9）Node.prototype.isEqualNode()，Node.prototype.isSameNode()：返回一个布尔值，用于检查两个节点是否相等。
      所谓相等的节点，指的是两个节点的类型相同、属性相同、子节点相同。
    10）Node.prototype.normalize()：用于清理当前节点内部的所有文本节点（text）。
      去除空的文本节点，并且将毗邻的文本节点合并成一个，也就是说不存在空的文本节点，以及毗邻的文本节点。
    11）Node.prototype.getRootNode()：返回当前节点所在文档的根节点document，与ownerDocument属性的作用相同。
      该方法可用于document节点自身，这一点与document.ownerDocument不同。
</pre>
      </div>

      <!-- NodeList接口，HTMLCollection接口 -->
      <div class="chapter" id='kp33'>
        <h2>kp33 NodeList接口，HTMLCollection接口</h2>
        <pre>
  1、节点都是单个对象，有时需要一种数据结构，能够容纳多个节点。
    DOM 提供两种节点集合，用于容纳多个节点：NodeList和HTMLCollection。
    这两种集合都属于接口规范。
    区别是，NodeList可以包含各种类型的节点，HTMLCollection只能包含 HTML 元素节点。
  2、NodeList 接口：一个类似数组的对象，它的成员是节点对象。
    获取：
      ·Node.childNodes
      ·document.querySelectorAll()等节点搜索方法
    NodeList实例很像数组，可以使用length属性和forEach方法。
    但是，它不是数组，不能使用pop或push之类数组特有的方法。
    目前，只有Node.childNodes返回的是一个动态集合，其他的 NodeList 都是静态集合。
    ·NodeList.prototype.length：返回 NodeList 实例包含的节点数量。
    ·NodeList.prototype.forEach()：用于遍历 NodeList 的所有成员。
      接受一个回调函数作为参数，每一轮遍历就执行一次这个回调函数
    ·NodeList.prototype.item()：接受一个整数值作为参数，表示成员的位置，返回该位置上的成员。
      所有类似数组的对象，都可以使用方括号运算符取出成员。一般情况下，都是使用方括号运算符，而不使用item方法。
    ·NodeList.prototype.keys()，NodeList.prototype.values()，NodeList.prototype.entries()
      都返回一个 ES6 的遍历器对象，可以通过for...of循环遍历获取每一个成员的信息。
      keys()返回键名的遍历器，values()返回键值的遍历器，entries()返回的遍历器同时包含键名和键值的信息。
  3、HTMLCollection接口：一个节点对象的集合，只能包含元素节点（element），不能包含其他类型的节点。
    是一个类似数组的对象，但是与NodeList接口不同，HTMLCollection没有forEach方法，只能使用for循环遍历。
    返回HTMLCollection实例的，主要是一些Document对象的集合属性，document.links、document.forms、document.images等。
    HTMLCollection实例都是动态集合，节点的变化会实时反映在集合中。
    ·HTMLCollection.prototype.length：返回HTMLCollection实例包含的成员数量。
    ·HTMLCollection.prototype.item()：接受一个整数值作为参数，表示成员的位置，返回该位置上的成员。
      方括号运算符也具有同样作用，而且使用更方便，所以一般情况下，总是使用方括号运算符。
    ·HTMLCollection.prototype.namedItem()：参数是一个字符串，表示id属性或name属性的值，返回对应的元素节点。
</pre>
      </div>

      <!-- ParentNode接口，ChildNode接口 -->
      <div class="chapter" id='kp34'>
        <h2>kp34 ParentNode接口，ChildNode接口</h2>
        <pre>
  1、ParentNode接口表示当前节点是一个父节点，提供一些处理子节点的方法。
    ChildNode接口表示当前节点是一个子节点，提供一些相关方法。
  2、ParentNode 接口：如果当前节点是父节点，就会混入了（mixin）ParentNode接口。
    只有元素节点（element）、文档节点（document）和文档片段节点（documentFragment）拥有子节点
    ·ParentNode.children：返回一个HTMLCollection实例，成员是当前节点的所有元素子节点。该属性只读。
    ·ParentNode.firstElementChild：返回当前节点的第一个元素子节点。
    ·ParentNode.lastElementChild：返回当前节点的最后一个元素子节点
    ·ParentNode.childElementCount：返回一个整数，表示当前节点的所有元素子节点的数目
    ·ParentNode.append()，ParentNode.prepend()
      append方法为当前节点追加一个或多个子节点，位置是最后一个元素子节点的后面。
        不仅可以添加元素子节点，还可以添加文本子节点。
      prepend方法为当前节点追加一个或多个子节点，位置是第一个元素子节点的前面。
        不仅可以添加元素子节点，还可以添加文本子节点。
  3、ChildNode 接口：如果一个节点有父节点，那么该节点就拥有了ChildNode接口。
    ·ChildNode.remove()：用于从父节点移除当前节点。（注意这是子节点主动移除）
    ·ChildNode.before()，ChildNode.after()：
      before方法用于在当前节点的前面，插入一个或多个同级节点。
        两者拥有相同的父节点。该方法不仅可以插入元素节点，还可以插入文本节点。
      after方法用于在当前节点的后面，插入一个或多个同级节点，两者拥有相同的父节点
        该方法不仅可以插入元素节点，还可以插入文本节点。
    ·ChildNode.replaceWith()：使用参数节点，替换当前节点。参数可以是元素节点，也可以是文本节点。
</pre>
      </div>

      <!-- Document节点 -->
      <div class="chapter" id='kp35'>
        <h2>kp35 Document节点</h2>
        <pre>
  1、document节点对象代表整个文档，每张网页都有自己的document对象。
    window.document属性就指向这个对象。（可以省略window）
    获取：
      ·正常的网页，直接使用document或window.document。
      ·iframe框架里面的网页，使用iframe节点的contentDocument属性。
      ·Ajax 操作返回的文档，使用XMLHttpRequest对象的responseXML属性。
      ·内部节点的ownerDocument属性。
    document对象继承了EventTarget接口和Node接口，并且混入（mixin）了ParentNode接口。
  2、属性
    1）快捷方式属性：指向文档内部的某个节点的快捷方式。
      ·document.defaultView：返回document对象所属的window对象。
        如果当前文档不属于window对象，该属性返回null。
      ·document.doctype：HTML的document对象一般有两个子节点。
        第一个子节点是document.doctype，指向< DOCTYPE>节点，
          即文档类型（Document Type Declaration，简写DTD）节点。
        如果网页没有声明 DTD，该属性返回null。
      ·document.documentElement：返回当前文档的根元素节点（root）。
        常是document节点的第二个子节点，紧跟在document.doctype节点后面。
      ·document.body属性指向< body>节点
        document.head属性指向< head>节点。
        如果网页源码里面省略了< head>或< body>，浏览器会自动创建。
      ·document.scrollingElement：返回文档的滚动元素。也就是说，当文档整体滚动时，到底是哪个元素在滚动。
        标准模式下，这个属性返回的文档的根元素document.documentElement（即< html>）。
        兼容（quirk）模式下，返回的是< body>元素，如果该元素不存在，返回null。
        document.scrollingElement.scrollTop = 0; // 页面滚动到浏览器顶部
      ·document.activeElement：返回获得当前焦点（focus）的 DOM 元素。
        常返回的是< input>、< textarea>、< select>等表单元素，如果当前没有焦点元素，返回< body>元素或null。
      ·document.fullscreenElement：返回当前以全屏状态展示的 DOM 元素。如果不是全屏状态，该属性返回null。
        通过document.fullscreenElement可以知道< video>元素有没有处在全屏状态，从而判断用户行为。
          document.fullscreenElement.nodeName == 'VIDEO'
    2）节点集合属性：属性返回一个HTMLCollection实例，表示文档内部特定元素的集合。
      ·document.links：当前文档所有设定了href属性的< a>及< area>节点。
      ·document.forms：所有< form>表单节点。除了使用位置序号，id属性和name属性也可以用来引用表单。
        document.forms[0] === document.forms.foo // true
        document.forms.bar === document.forms.foo // true
      ·document.images：页面所有< img>图片节点。
      ·document.embeds和document.plugins：所有< embed>节点。
      ·document.scripts：返回所有< scrip t>节点。
      ·document.styleSheets：返回文档内嵌或引入的样式表集合
    3）文档静态信息属性：返回文档信息。
      ·document.documentURI属性和document.URL属性：返回一个字符串，表示当前文档的网址。
        documentURI继承自Document接口，可用于所有文档；URL继承自HTMLDocument接口，只能用于 HTML 文档。
        如果文档的锚点（#anchor）变化，这两个属性都会跟着变化。
      ·document.domain：返回当前文档的域名，不包含协议和端口。
      ·document.location：通过window.location和document.location属性，可以拿到这个Location对象。
      ·document.lastModified：返回一个字符串，表示当前文档最后修改的时间。
        注意，返回值是字符串，所以不能直接用来比较。Date.parse方法将其转为Date实例，才能比较两个网页。
      ·document.title：返回当前文档的标题。
        默认情况下，返回< title>节点的值。但是该属性是可写的，一旦被修改，就返回修改后的值。
      ·document.characterSet：返回当前文档的编码，比如UTF-8、ISO-8859-1等等。
      ·document.referrer：返回一个字符串，表示当前文档的访问者来自哪里。
        如果无法获取来源，或者用户直接键入网址而不是从其他网页点击进入，document.referrer返回一个空字符串。
        document.referrer的值，总是与 HTTP 头信息的Referer字段保持一致。
      ·document.dir：返回一个字符串，表示文字方向。
      ·document.compatMode：返回浏览器处理文档的模式，为BackCompat（向后兼容模式）和CSS1Compat（严格模式）。
    4）文档状态属性
      ·document.hidden属性返回一个布尔值，表示当前页面是否可见。
        如果窗口最小化、浏览器切换了 Tab，都会导致导致页面不可见，使得document.hidden返回true。
      ·document.visibilityState返回文档的可见状态。
        ·visible：页面可见。注意，页面可能是部分可见，即不是焦点窗口，前面被其他窗口部分挡住了。
        ·hidden：页面不可见，有可能窗口最小化，或者浏览器切换到了另一个 Tab。
        ·prerender：页面处于正在渲染状态，对于用户来说，该页面不可见。
        ·unloaded：页面从内存里面卸载了。
        可以用在页面加载时，防止加载某些资源；或者页面不可见时，停掉一些页面功能。
      ·document.readyState：返回当前文档的状态，共有三种可能的值。
        loading：加载 HTML 代码阶段（尚未完成解析）
          浏览器遇到 HTML 文档中的< scrip t>元素，并且没有async或defer属性，
          就暂停解析，开始执行脚本，这时document.readyState属性还是等于loading。
        interactive：加载外部资源阶段
        complete：加载完成
      ·document.cookie：用来操作浏览器 Cookie
      ·document.designMode：控制当前文档是否可编辑。该属性只有两个值on和off
      ·document.implementation：返回一个DOMImplementation对象
  3、方法
    ·document.open()，document.close()
      document.open方法清除当前文档所有内容，使得文档处于可写状态，供document.write方法写入内容。
      document.close方法用来关闭document.open()打开的文档。
    ·document.write()，document.writeln()
      document.write方法用于向当前文档写入内容。
      在网页的首次渲染阶段，即没有执行document.close()，document.write写入的内容就会追加在已有内容的后面。
      注意，document.write会当作 HTML 代码解析，不会转义。
      除了某些特殊情况，应该尽量避免使用document.write这个方法。
      document.writeln方法与write方法完全一致，除了会在输出内容的尾部添加换行符。
    ·document.querySelector()，document.querySelectorAll()
      querySelector方法接受一个 CSS 选择器作为参数，返回匹配该选择器的元素节点。
        如果有多个节点满足匹配条件，则返回第一个匹配的节点。
      querySelectorAll方法是返回一个NodeList对象，包含所有匹配给定选择器的节点。
      可以是逗号分隔的多个 CSS 选择器，返回匹配其中一个选择器的元素节点，这与 CSS 选择器的规则是一致的。
      但是，它们不支持 CSS 伪元素的选择器和伪类的选择器
      querySelectorAll的返回结果不是动态集合，不会实时反映元素节点的变化。
      除了定义在document对象上，还定义在元素节点上，即在元素节点上也可以调用。
    ·document.getElementsByTagName()：搜索 HTML 标签名，返回符合条件的元素。
      返回值是一个类似数组对象（HTMLCollection实例），可以实时反映 HTML 文档的变化。
    ·document.getElementsByClassName()：返回一个类似数组的对象（HTMLCollection实例），
      包括了所有class名字符合指定条件的元素，元素的变化实时反映在返回结果中。
    ·document.getElementsByName()：用于选择拥有name属性的 HTML 元素
    ·document.getElementById()：返回匹配指定id属性的元素节点。
      这个方法只能在document对象上使用，不能在其他元素节点上使用。
    ·document.elementFromPoint()，document.elementsFromPoint()
      elementFromPoint方法返回位于页面指定位置最上层的元素节点。
        两个参数，依次是相对于当前视口左上角的横坐标和纵坐标，单位是像素。
      elementsFromPoint()返回一个数组，成员是位于指定坐标（相对于视口）的所有元素。
    ·document.createElement()：用来生成元素节点，并返回该节点。
      参数为元素的标签名，即元素节点的tagName属性，如果参数里面包含尖括号（即< 和 >）会报错。
    ·document.createTextNode()：用来生成文本节点（Text实例），并返回该节点。它的参数是文本节点的内容。
      可以确保返回的节点，被浏览器当作文本渲染，而不是当作 HTML 代码渲染。因此，可以用来展示用户的输入，避免 XSS 攻击。
      createTextNode方法对大于号和小于号进行转义，从而保证即使用户输入的内容包含恶意代码，也能正确显示。
      需要注意的是，该方法不对单引号和双引号转义，所以不能用来对 HTML 属性赋值。
    ·document.createAttribute()：生成一个新的属性节点（Attr实例），并返回它。参数name，是属性的名称。
    ·document.createComment()：生成一个新的注释节点，并返回该节点。
    ·document.createDocumentFragment()：生成一个空的文档片段对象（DocumentFragment实例）。
      DocumentFragment是一个存在于内存的DOM片段，不属于当前文档，常常用来生成一段较复杂的DOM结构，然后再插入当前文档。
      DocumentFragment不属于当前文档，对它的任何改动，都不会引发网页的重新渲染，比直接修改当前文档的DOM有更好的性能表现。
    ·document.createEvent()：生成一个事件对象（Event实例），该对象可以被element.dispatchEvent方法使用，触发指定事件。
      参数是事件类型，比如UIEvents、MouseEvents、MutationEvents、HTMLEvents。
    ·document.addEventListener()，document.removeEventListener()，document.dispatchEvent()
      用于处理document节点的事件。它们都继承自EventTarget接口
    ·document.hasFocus()：返回一个布尔值，表示当前文档之中是否有元素被激活或获得焦点。
    ·document.adoptNode()，document.importNode()
      adoptNode方法将某个节点及其子节点，从原来所在的文档或DocumentFragment里面移除，归属当前document对象，返回该节点
      importNode方法则是从原来所在的文档或DocumentFragment里面，拷贝某个节点及其子节点，让它们归属当前document对象
        第一个参数是外部节点，第二个参数是一个布尔值，表示对外部节点是深拷贝还是浅拷贝，默认是浅拷贝（false）
      只是改变了节点的归属，并没有将这个节点插入新的文档树
    ·document.createNodeIterator()：返回一个子节点遍历器。
    ·document.createTreeWalker()：返回一个 DOM 的子树遍历器
    ·document.execCommand()，document.queryCommandSupported()，document.queryCommandEnabled()
      如果document.designMode属性设为on，那么整个文档用户可编辑；如果元素的contenteditable属性设为true，那么该元素可编辑。
        这两种情况下，可以使用document.execCommand()方法，改变内容的样式，比如document.execCommand('bold')会使得字体加粗。
        这个方法大部分情况下，只对选中的内容生效。如果有多个内容可编辑区域，那么只对当前焦点所在的元素生效。
      queryCommandSupported()方法返回一个布尔值，表示浏览器是否支持document.execCommand()的某个命令。
      queryCommandEnabled()方法返回一个布尔值，表示当前是否可用document.execCommand()的某个命令
    ·document.getSelection()：指向window.getSelection()
</pre>
      </div>

      <!-- Element节点 -->
      <div class="chapter" id='kp36'>
        <h2>kp36 Element节点</h2>
        <pre>
  1、每一个 HTML 元素，在 DOM 树上都会转化成一个Element节点对象（以下简称元素节点）。
    元素节点的nodeType属性都是1。
    元素节点不是一种对象，而是一组对象，这些对象除了继承Element的属性和方法，还有各自构造函数的属性和方法。
  2、实例属性
    ·元素特性的相关属性
      ·Element.id属性返回指定元素的id属性，该属性可读写。
      ·Element.tagName属性返回指定元素的大写标签名，与nodeName属性的值相等。
      ·Element.dir属性用于读写当前元素的文字方向，可能是从左到右（"ltr"），也可能是从右到左（"rtl"）。
      ·Element.accessKey属性用于读写分配给当前元素的快捷键。
      ·Element.draggable属性返回一个布尔值，表示当前元素是否可拖动。该属性可读写。
      ·Element.lang属性返回当前元素的语言设置。该属性可读写。
      ·Element.tabIndex属性返回一个整数，表示当前元素在 Tab 键遍历时的顺序。该属性可读写。
      ·Element.title属性用来读写当前元素的 HTML 属性title。该属性通常用来指定，鼠标悬浮时弹出的文字提示框。
    ·元素状态的相关属性
      ·Element.hidden属性返回一个布尔值，表示当前元素的hidden属性，用来控制当前元素是否可见。该属性可读写。
        注意，该属性与 CSS 设置是互相独立的。这个属性并不能用来判断当前元素的实际可见性。
        这个属性只在 CSS 没有明确设定当前元素的可见性时才有效。
      ·Element.contentEditable，Element.isContentEditable
        设置contentEditable属性，使得元素的内容可以编辑。
        contentEditable属性返回一个字符串，表示是否设置了contenteditable属性。该属性可写。
          "true"：元素内容可编辑、"false"：元素内容不可编辑、"inherit"：元素是否可编辑，继承了父元素的设置
        isContentEditable属性返回一个布尔值，同样表示是否设置了contenteditable属性。该属性只读。
      ·Element.attributes属性返回一个类似数组的对象，成员是当前元素节点的所有属性节点
      ·Element.className，Element.classList
        className属性用来读写当前元素节点的class属性。它的值是一个字符串，每个class之间用空格分割。
        classList属性返回一个类似数组的对象，当前元素节点的每个class就是这个对象的一个成员。有：
          add()：增加一个 class。
          remove()：移除一个 class。
          contains()：检查当前元素是否包含某个 class。
          toggle()：将某个 class 移入或移出当前元素。
            可以接受一个布尔值，作为第二个参数。如果为true，则添加该属性；如果为false，则去除该属性。
          item()：返回指定索引位置的 class。
          toString()：将 class 的列表转为字符串。
      ·Element.dataset：返回一个对象，可以从这个对象读写data-属性。
        网页元素可以自定义data-属性，用来添加数据。 < div data-timestamp="1522907809292">< /div>
          div.dataset.timestamp // "1522907809292"
        注意，dataset上面的各个属性返回都是字符串。
        data-abc-def对应dataset.abcDef，data-abc-1对应dataset["abc-1"]。
        也可以使用Element.getAttribute()和Element.setAttribute()，通过完整的属性名读写这些属性。
      ·Element.innerHTML：返回一个字符串，等同于该元素包含的所有 HTML 代码。
        innerHTML属性会将它们转为实体形式& amp;、& lt;、& gt;。
        如果想得到原文，建议使用element.textContent属性。
        写入的时候，如果插入的文本包含 HTML 标签，会被解析成为节点对象插入 DOM。
        注意，如果文本之中含有< scrip t>标签，虽然可以生成script节点，但是插入的代码不会执行。
        为了安全考虑，如果插入的是文本，最好用textContent属性代替innerHTML。
      ·Element.outerHTML：返回一个字符串，表示当前元素节点的所有 HTML 代码，包括该元素本身和所有子元素。
        属性是可读写的，对它进行赋值，等于替换掉当前元素。被替换的元素还存在于内存中。
        注意，如果一个节点没有父节点，设置outerHTML属性会报错。
      ·Element.clientHeight，Element.clientWidth
        clientHeight属性返回一个整数值，表示元素节点的 CSS 高度（单位像素），只对块级元素生效，对于行内元素返回0
          除了元素本身的高度，它还包括padding部分，但是不包括border、margin。
          如果有水平滚动条，还要减去水平滚动条的高度。注意，这个值始终是整数，如果是小数会被四舍五入。
        clientWidth同理
        document.documentElement的clientHeight属性，返回当前视口的高度（即浏览器窗口的高度），
          等同于window.innerHeight属性减去水平滚动条的高度（如果有的话）。
        document.body的高度则是网页的实际高度。
        一般来说，document.body.clientHeight大于document.documentElement.clientHeight。
      ·Element.clientLeft，Element.clientTop
        clientLeft属性等于元素节点左边框（left border）的宽度（单位像素），不包括左侧的padding和margin
        clientTop同理
      ·Element.scrollHeight，Element.scrollWidth
        返回一个整数值（小数会四舍五入），表示当前元素的总高度（单位像素），包括溢出容器、当前不可见的部分。
        包括padding、伪元素的高度，但不包括border、margin以及水平滚动条的高度（如果有水平滚动条的话）。
        注意，如果元素节点的内容出现溢出，即使溢出的内容是隐藏的，scrollHeight属性仍然返回元素的总高度。
      ·Element.scrollLeft，Element.scrollTop
        表示当前元素的垂直滚动条向下滚动的像素数量。对于那些没有滚动条的网页元素，这两个属性总是等于0。
        查看整张网页的水平的和垂直的滚动距离，要从document.documentElement元素上读取。
        属性都可读写，设置该属性的值，会导致浏览器将当前元素自动滚动到相应的位置。
      ·Element.offsetParent：返回最靠近当前元素的、并且 CSS 的position属性不等于static的上层元素。
      ·Element.offsetHeight，Element.offsetWidth
        返回一个整数，表示元素的CSS垂直高度（单位像素），包括元素本身的高度、padding和border，以及水平滚动条的高度。
        只比Element.clientHeight和Element.clientWidth多了边框的高度或宽度，以及padding
      ·Element.offsetLeft，Element.offsetTop：返回当前元素左上角相对于Element.offsetParent节点的水平或垂直位移，
      ·Element.style：用来读写该元素的行内样式信息
      ·Element.children，Element.childElementCount
        children返回一个类似数组的对象（HTMLCollection实例），包括当前元素节点的所有子元素。
          与Node.childNodes属性的区别是，它只包括元素类型的子节点，不包括其他类型的子节点。
        childElementCount属性返回当前元素节点包含的子元素节点的个数
      ·Element.firstElementChild，Element.lastElementChild：返回当前元素的第一个或最后一个元素子节点
      ·Element.nextElementSibling，Element.previousElementSibling
        返回当前元素节点的后一个或前一个同级元素节点
  3、实例方法
    getAttribute()：读取某个属性的值
    getAttributeNames()：返回当前元素的所有属性名
    setAttribute()：写入属性值
    hasAttribute()：某个属性是否存在
    hasAttributes()：当前元素是否有属性
    removeAttribute()：删除属性
  4、属性相关方法
    ·Element.querySelector()：接受 CSS 选择器作为参数，返回父元素的第一个匹配的子元素
      注意，这个方法无法选中伪元素。
    ·Element.querySelectorAll()：接受 CSS 选择器作为参数，返回一个NodeList实例，包含所有匹配的子元素。
    ·Element.getElementsByClassName()：返回一个HTMLCollection实例，动态集合
    ·Element.getElementsByTagName()：返回一个HTMLCollection实例
      成员是当前节点的所有匹配指定标签名的子元素节点
    ·Element.closest()
      接受一个 CSS 选择器作为参数，返回匹配该选择器的、最接近当前节点的一个祖先节点（包括当前节点本身）
    ·Element.matches()：返回一个布尔值，表示当前元素是否匹配给定的 CSS 选择器。
  5、事件相关方法：都继承自EventTarget接口
    Element.addEventListener()：添加事件的回调函数
    Element.removeEventListener()：移除事件监听函数
    Element.dispatchEvent()：触发事件
    ·Element.scrollIntoView()：滚动当前元素，进入浏览器的可见区域
      类似于设置window.location.hash的效果。
      接受一个布尔值作为参数。默认为true。
      如果为true，表示元素的顶部与当前区域的可见部分的顶部对齐（前提是当前区域可滚动）；
      如果为false，表示元素的底部与当前区域的可见部分的尾部对齐（前提是当前区域可滚动）。
    ·Element.getBoundingClientRect()
      返回一个对象，提供当前元素节点的大小、位置等信息，基本上就是CSS盒状模型的所有信息。
      如果想得到绝对位置，可以将left属性加上window.scrollX，top属性加上window.scrollY。
      所有属性，都把边框（border属性）算作元素的一部分。也就是说，都是从边框外缘的各个点来计算。
      因此，width和height包括了元素本身 + padding + border。
    ·Element.getClientRects()：返回一个类似数组的对象，里面是当前元素在页面上形成的所有矩形
      对于行内元素，该方法返回的对象有多少个成员，取决于该元素在页面上占据多少行。
      这个方法主要用于判断行内元素是否换行，以及行内元素的每一行的位置偏移。
      注意，如果行内元素包括换行符，那么该方法会把换行符考虑在内。
    ·Element.insertAdjacentElement()
      在相对于当前元素的指定位置，插入一个新的节点。该方法返回被插入的节点，如果插入失败，返回null。
    ·Element.insertAdjacentHTML()，Element.insertAdjacentText()
      insertAdjacentHTML方法用于将一个 HTML 字符串，解析生成 DOM 结构，插入相对于当前节点的指定位置。
      insertAdjacentText方法在相对于当前节点的指定位置，插入一个文本节点 
    ·Element.remove()：继承自 ChildNode 接口，用于将当前元素节点从它的父节点移除。
    ·Element.focus()，Element.blur()
      focus方法用于将当前页面的焦点，转移到指定元素上。
      blur方法用于将焦点从当前元素移除。
    ·Element.click()：用于在当前元素上模拟一次鼠标点击，相当于触发了click事件。
</pre>
      </div>

      <!-- 属性的操作 -->
      <div class="chapter" id='kp37'>
        <h2>kp37 属性的操作</h2>
        <pre>
  1、HTML 元素包括标签名和若干个键值对，这个键值对就称为“属性”（attribute）。
    属性本身是一个对象（Attr对象）
  2、Element.attributes 属性：返回一个类似数组的动态对象，成员是该元素标签的所有属性节点对象（动态）
    属性节点对象有name和value属性，对应该属性的属性名和属性值，等同于nodeName属性和nodeValue属性。
  3、元素的标准属性：HTML 元素的标准属性（即在标准中定义的属性），会自动成为元素节点对象的属性。
  4、属性操作的标准方法
    Element.getAttribute()：返回当前元素节点的指定属性。
    Element.getAttributeNames()：返回一个数组，成员是当前元素的所有属性的名字。
    Element.setAttribute()：用于为当前元素节点新增属性。如果同名属性已存在，则相当于编辑已存在的属性。
      属性值总是字符串，其他类型的值会自动转成字符串
      有些属性不需要属性值，只要设置了就总是会生效
    Element.hasAttribute()：返回一个布尔值，表示当前元素节点是否包含指定属性。
    Element.hasAttributes()：返回一个布尔值，表示当前元素是否有属性
    Element.removeAttribute()：移除指定属性
  5、dataset 属性：使用标准提供的data-*属性。在HTML元素上附加数据，供 JavaScript 脚本使用
    使用元素节点对象的dataset属性，它指向一个对象，可以用来操作 HTML 元素标签的data-*属性。
    删除一个data-*属性，可以直接使用delete命令。
    注意，data-后面的属性名有限制，只能包含字母、数字、连词线（-）、点（.）、冒号（:）和下划线（_)。
    而且，属性名不应该使用A到Z的大写字母，比如不能有data-helloWorld这样的属性名，而要写成data-hello-world。
    转成dataset的键名时，变为相应的驼峰法
</pre>
      </div>

      <!-- Text节点和DocumentFragment节点 -->
      <div class="chapter" id='kp38'>
        <h2>kp38 Text节点和DocumentFragment节点</h2>
        <pre>
  1、文本节点（Text）代表元素节点（Element）和属性节点（Attribute）的文本内容
    用父节点的firstChild、nextSibling等属性获取文本节点，
    或者使用Document节点的createTextNode方法创造一个文本节点。
    浏览器原生提供一个Text构造函数。它返回一个文本节点实例。它的参数就是该文本节点的文本内容。
    注意，由于空格也是一个字符，所以哪怕只有一个空格，也会形成文本节点。
    文本节点除了继承Node接口，还继承了CharacterData接口
  2、Text节点的属性
    ·data：等同于nodeValue属性，用来设置或读取文本节点的内容。
    ·wholeText：将当前文本节点与毗邻的文本节点，作为一个整体返回
    ·length：返回当前文本节点的文本长度。
    ·nextElementSibling，previousElementSibling：返回紧跟在当前文本节点后面的那个同级元素节点
  3、Text节点的方法
    ·appendData()：在Text节点尾部追加字符串。
    ·deleteData()：删除Text节点内部的子字符串，第一个参数为子字符串开始位置，第二个参数为子字符串长度。
    ·insertData()：在Text节点插入字符串，第一个参数为插入位置，第二个参数为插入的子字符串。
    ·replaceData()：用于替换文本，第一个参数为替换开始位置，第二个参数为需要被替换掉的长度，第三个参数为新加入的字符串。
    ·subStringData()：用于获取子字符串，第一个参数为子字符串在Text节点中的开始位置，第二个参数为子字符串长度。
    ·remove()：用于移除当前Text节点。
    ·splitText()：将Text节点一分为二，变成两个毗邻的Text节点
      返回分割位置后方的字符串，而原Text节点变成只包含分割位置前方的字符串。
      父元素节点的normalize方法可以将毗邻的两个Text节点合并。
  4、DocumentFragment节点：代表一个文档的片段，本身就是一个完整的 DOM 树形结构
    它不属于当前文档，操作DocumentFragment节点，要比直接操作 DOM 树快得多。（内存中，无需渲染）
    一般用于构建一个 DOM 结构，然后插入当前文档。
    document.createDocumentFragment方法、浏览器原生的DocumentFragment构造函数，可以创建一个空的DocumentFragment节点。
    DocumentFragment节点本身不能被插入当前文档。
      作为appendChild()、insertBefore()、replaceChild()等方法的参数时，是它的所有子节点插入当前文档，而不是它自身。
    一旦DocumentFragment节点被添加进当前文档，它自身就变成了空节点（textContent属性为空字符串），可以被再次使用
    如果想要保存DocumentFragment节点的内容，可以使用cloneNode方法。
</pre>
      </div>

      <!-- CSS操作 -->
      <div class="chapter" id='kp39'>
        <h2>kp39 CSS操作</h2>
        <pre>
  1、HTML元素的style属性
    使用网页元素节点的getAttribute()方法、setAttribute()方法和removeAttribute()方法，
      直接读写或删除网页元素的style属性。
  2、CSSStyleDeclaration接口：CSSStyleDeclaration 接口可以直接读写 CSS 的样式属性
    不过，连词号需要变成骆驼拼写法。
    三个地方部署了这个接口：元素节点的style属性（Element.style）、CSSStyle实例的style属性
      window.getComputedStyle()的返回值
  3、CSSStyleDeclaration实例属性
    ·cssText：用来读写当前规则的所有样式声明文本。
      删除一个元素的所有行内样式，最简便的方法就是设置cssText为空字符串。
    ·length：返回一个整数值，表示当前规则包含多少条样式声明。
    ·parentRule：返回当前规则所属的那个样式块（CSSRule实例）。只读，且只在使用CSSRule接口时有意义。
  4、CSSStyleDeclaration实例方法
    ·getPropertyPriority：接受 CSS 样式的属性名作为参数，返回一个字符串，表示有没有设置important优先级。
      如果有就返回important，否则返回空字符串。
    ·getPropertyValue：接受 CSS 样式属性名作为参数，返回一个字符串，表示该属性的属性值。
    ·item：接受一个整数值作为参数，返回该位置的 CSS 属性名。
    ·removeProperty：接受一个属性名作为参数，在 CSS 规则里面移除这个属性，返回这个属性原来的值。
    ·setProperty：用来设置新的 CSS 属性。
  5、CSS模块的侦测：需要知道当前浏览器是否支持某个模块，这就叫做“CSS模块的侦测”。
    一个比较普遍适用的方法是，判断元素的style对象的某个属性值是否为字符串。
    如果该 CSS 属性确实存在，会返回一个字符串。如果该属性不存在，则会返回undefined。
  6、CSS对象：浏览器原生提供 CSS 对象
    ·CSS.escape()：转义 CSS 选择器里面的特殊字符。
    ·CSS.supports()：返回一个布尔值，表示当前环境是否支持某一句 CSS 规则。
  7、window.getComputedStyle()：得到元素实际的样式，需要得到浏览器最终计算出来的样式规则。只读
    行内样式（inline style）具有最高的优先级，改变行内样式，通常会立即反映出来。
    但是，网页元素最终的样式是综合各种规则计算出来的
    CSSStyleDeclaration实例是动态对象，任何对于样式的修改，会实时反映到这个实例上面。
  8、CSS伪元素：通过CSS向DOM添加的元素，主要是通过:before和:after选择器生成，然后用content属性指定伪元素的内容。
    要用到window.getComputedStyle()获取伪元素，window.getComputedStyle(test, ':before').content;
    也可以使用 CSSStyleDeclaration 实例的getPropertyValue方法，获取伪元素的属性。
  9、StyleSheet接口：StyleSheet接口代表网页的一张样式表，包括< lin k>元素加载的样式表和< styl e>元素内嵌的样式表。
    document对象的styleSheets属性，可以返回当前页面的所有StyleSheet实例（即所有样式表）。类似数组
    ·实例属性
      ·disabled：返回一个布尔值，表示该样式表是否处于禁用状态。
        设置disabled属性为true，等同于在< lin k>元素里面，将这张样式表设为alternate stylesheet，样式表将不会生效。
      ·media：返回一个类似数组的对象（MediaList实例），成员是表示适用媒介的字符串。
        表示当前样式表是用于屏幕（screen），还是用于打印（print）或手持设备（handheld），或各种媒介都适用（all）。
        该属性只读，默认值是screen。
        MediaList实例的appendMedium方法，用于增加媒介；deleteMedium方法用于删除媒介。
      ·title：返回样式表的title属性。
      ·type：返回样式表的type属性，通常是text/css。
      ·parentStyleSheet：返回包含了当前样式表的那张样式表。
        CSS 的@import命令允许在样式表中加载其他样式表。
      ·ownerNode：返回StyleSheet对象所在的 DOM 节点，通常是< lin k>或< styl e>。
      ·cssRules：指向一个类似数组的对象（CSSRuleList实例），里面每一个成员就是当前样式表的一条 CSS 规则。
        使用该规则的cssText属性，可以得到 CSS 规则对应的字符串。
        每条 CSS 规则还有一个style属性，指向一个对象，用来读写具体的 CSS 命令。
      ·有些样式表是通过@import规则输入的，它的ownerRule属性会返回一个CSSRule实例，代表那行@import规则
    ·实例方法 
      ·CSSStyleSheet.insertRule方法用于在当前样式表的插入一个新的 CSS 规则。
      ·CSSStyleSheet.deleteRule方法用来在样式表里面移除一条规则，参数是该条规则在cssRules对象中的位置。
  10、实例：添加样式表
    ·一种是添加一张内置样式表，即在文档中添加一个< styl e>节点。
    ·一种是添加外部样式表，即在文档中添加一个< lin k>节点，然后将href属性指向外部样式表的 URL。
  11、CSSRuleList接口：一个类似数组的对象，表示一组 CSS 规则，成员都是 CSSRule 实例。
    获取 CSSRuleList 实例，一般是通过StyleSheet.cssRules属性。
    每一条规则（CSSRule 实例）可以通过rules.item(index)或者rules[index]拿到。
  12、CSSRule 接口：JavaScript 通过 CSSRule 接口操作 CSS 规则。
    一条 CSS 规则包括两个部分：CSS 选择器和样式声明。
    一般通过 CSSRuleList 接口（StyleSheet.cssRules）获取 CSSRule 实例。
  13、CSSRule 实例的属性
    ·CSSRule.cssText属性返回当前规则的文本，还是使用上面的例子。
    ·CSSRule.parentStyleSheet属性返回当前规则所在的样式表对象（StyleSheet 实例）
    ·CSSRule.parentRule属性返回包含当前规则的父规则
    ·CSSRule.type属性返回一个整数值，表示当前规则的类型。
      1：普通样式规则（CSSStyleRule实例）、3：@import规则、4：@media规则（CSSMediaRule实例）、5：@font-face规则
  14、CSSStyleRule接口：
    ·CSSStyleRule.selectorText属性返回当前规则的选择器。属性是可写的。
    ·CSSStyleRule.style属性返回一个对象（CSSStyleDeclaration 实例），代表当前规则的样式声明，
      也就是选择器后面的大括号里面的部分。
  15、CSSMediaRule 接口：主要提供media属性和conditionText属性。
    前者返回代表@media规则的一个对象（MediaList 实例），后者返回@media规则的生效条件。
  16、window.matchMedia()：用来将 CSS 的MediaQuery条件语句，转换成一个 MediaQueryList 实例。
    MediaQueryList 接口的实例属性：
      media属性返回一个字符串，表示对应的 MediaQuery 条件语句。
      matches属性返回一个布尔值，表示当前页面是否符合指定的 MediaQuery 条件语句。
      onchange属性用来指定change事件的监听函数。
        如果 MediaQuery 条件语句的适配环境发生变化，会触发change事件。
    MediaQueryList 接口的实例方法：
      MediaQueryList.addListener()和MediaQueryList.removeListener()，用来为change事件添加或撤销监听函数。
</pre>
      </div>

      <!-- Mutation Observer API -->
      <div class="chapter" id='kp40'>
        <h2>kp40 Mutation Observer API</h2>
        <pre>
  1、Mutation Observer API 用来监视 DOM 变动。
    DOM 的任何变动，比如节点的增减、属性的变动、文本内容的变动，这个 API 都可以得到通知。
    事件是同步触发，也就是说，DOM 的变动立刻会触发相应的事件；
    Mutation Observer 则是异步触发，DOM 的变动并不会马上触发，而是要等到当前所有 DOM 操作都结束才触发。
    这样设计是为了应付 DOM 变动频繁的特点。
      ·它等待所有脚本任务完成后，才会运行（即异步触发方式）。
      ·它把 DOM 变动记录封装成一个数组进行处理，而不是一条条个别处理 DOM 变动。
      ·它既可以观察 DOM 的所有类型变动，也可以指定只观察某一类变动。
  2、MutationObserver 构造函数
    使用MutationObserver构造函数，新建一个观察器实例，同时指定这个实例的回调函数。
    回调函数接受两个参数，第一个是变动数组，第二个是观察器实例
  3、MutationObserver 的实例方法
    ·observe方法用来启动监听，它接受两个参数。
      第一个参数：所要观察的 DOM 节点
      第二个参数：一个配置对象，指定所要观察的特定变动
      像使用addEventListener方法一样，多次添加同一个观察器是无效的，回调函数依然只会触发一次。
      如果指定不同的options对象，以后面添加的那个为准，类似覆盖。
    ·disconnect方法用来停止观察。调用该方法后，DOM 再发生变动，也不会触发观察器。
    ·takeRecords方法用来清除变动记录，即不再处理未处理的变动。该方法返回变动记录的数组。
  4、MutationRecord 对象
    DOM 每次发生变化，就会生成一条变动记录（MutationRecord 实例），包含了与变动相关的所有信息。
    Mutation Observer 处理的就是一个个MutationRecord实例所组成的数组。
</pre>
      </div>

      <!-- EventTarget接口 -->
      <div class="chapter" id='kp41'>
        <h2>kp41 EventTarget接口</h2>
        <pre>
  1、DOM的事件操作（监听和触发），都定义在EventTarget接口。
  2、EventTarget.addEventListener()用于在当前节点或对象上，定义一个特定事件的监听函数。
    针对当前对象的同一个事件，添加多个不同的监听函数。这些函数按照添加顺序触发，即先添加先触发。
    如果为同一个事件多次添加同一个监听函数，该函数只会执行一次，
  3、EventTarget.removeEventListener方法用来移除addEventListener方法添加的事件监听函数
  4、EventTarget.dispatchEvent方法在当前节点上触发指定事件，从而触发监听函数的执行。
</pre>
      </div>

      <!-- 事件模型 -->
      <div class="chapter" id='kp42'>
        <h2>kp42 事件模型</h2>
        <pre>
  1、浏览器的事件模型，就是通过监听函数（listener）对事件做出反应。
    事件发生后，浏览器监听到了这个事件，就会执行对应的监听函数。
    事件驱动编程模式（event-driven）的主要编程方式。
  2、HTML 的 on- 属性：直接定义某些事件的监听代码。
    直接设置on-属性，与通过元素节点的setAttribute方法设置on-属性，效果是一样的。
    使用这个方法指定的监听代码，只会在冒泡阶段触发。
    违反了 HTML 与 JavaScript 代码相分离的原则，将两者写在一起，不利于代码分工，不推荐使用。
  3、元素节点对象的事件属性，同样可以指定监听函数。
    使用这个方法指定的监听代码，只会在冒泡阶段触发。
    同一个事件只能定义一个监听函数，如果定义两次onclick属性，后一次定义会覆盖前一次。也不推荐使用。
  4、所有 DOM 节点实例都有addEventListener方法，用来为该节点定义事件的监听函数。
    同一个事件可以添加多个监听函数。能够指定在哪个阶段（捕获阶段还是冒泡阶段）触发监听函数。
    除了 DOM 节点，其他对象也有这个接口，它等于是整个 JavaScript 统一的监听函数接口。
  5、监听函数内部的this指向触发事件的那个元素节点。
  6、事件的传播
    一个事件发生后，会在子元素和父元素之间传播（propagation）。这种传播分成三个阶段。
    第一阶段：从window对象传导到目标节点（上层传到底层），称为“捕获阶段”（capture phase）。
    第二阶段：在目标节点上触发，称为“目标阶段”（target phase）。
    第三阶段：从目标节点传导回window对象（从底层传回上层），称为“冒泡阶段”（bubbling phase）。
    三阶段的传播模型，使得同一个事件会在多个节点上触发。
  7、事件的代理（delegation）
    事件会在冒泡阶段向上传播到父节点，可以把子节点的监听函数定义在父节点上，由父节点的监听函数统一处理多个子元素的事件。
    只要定义一个监听函数，就能处理多个子节点的事件，而不用在每个< li>节点上定义监听函数。
    如果希望事件到某个节点为止，不再传播，可以使用事件对象的stopPropagation方法。
    stopPropagation方法只会阻止事件的传播，不会阻止该事件触发< p>节点的其他click事件的监听函数。
    如果想要彻底取消该事件，不再触发后面所有click的监听函数，可以使用stopImmediatePropagation方法。
</pre>
      </div>

      <!-- Event对象 -->
      <div class="chapter" id='kp43'>
        <h2>kp43 Event对象</h2>
        <pre>
  1、事件发生以后，会产生一个事件对象，作为参数传给监听函数。
    浏览器原生提供一个Event对象，所有的事件都是这个对象的实例，或者说继承了Event.prototype对象。
    Event构造函数接受两个参数。第一个参数type是字符串，表示事件的名称；第二个参数options是一个对象，表示事件对象的配置。
  2、Event实例属性
    Event.bubbles属性返回一个布尔值，表示当前事件是否会冒泡。只读属性
    Event.eventPhase属性返回一个整数常量，表示事件目前所处的阶段。该属性只读。
    Event.cancelable属性返回一个布尔值，表示事件是否可以取消。只读
      如果事件不能取消，调用Event.preventDefault()会没有任何效果。
    Event.cancelBubble属性是一个布尔值，如果设为true，相当于执行Event.stopPropagation()，可以阻止事件的传播。
    Event.defaultPrevented属性返回一个布尔值，表示该事件是否调用过Event.preventDefault方法
    Event.currentTarget属性返回事件当前所在的节点，即事件当前正在通过的节点，也就是当前正在执行的监听函数所在的那个节点
      随着事件的传播，这个属性的值会变。e.currentTarget总是等同于监听函数内部的this。
    Event.target属性返回原始触发事件的那个节点，即事件最初发生的节点。这个属性不会随着事件的传播而改变。
    Event.type属性返回一个字符串，表示事件类型。事件的类型是在生成事件的时候指定的。该属性只读。
    Event.timeStamp属性返回一个毫秒时间戳，表示事件发生的时间。它是相对于网页加载成功开始计算的。
    Event.isTrusted属性返回一个布尔值，表示该事件是否由真实的用户行为产生。
      比如，用户点击链接会产生一个click事件，该事件是用户产生的；Event构造函数生成的事件，则是脚本产生的。
    Event.detail属性只有浏览器的 UI （用户界面）事件才具有。该属性返回一个数值，表示事件的某种信息。具体含义与事件类型相关
  3、Event实例方法
    Event.preventDefault方法取消浏览器对当前事件的默认行为
      前提是，事件对象的cancelable属性为true，如果为false，调用该方法没有任何效果。
      注意，该方法只是取消事件对当前元素的默认影响，不会阻止事件的传播。
      利用这个方法，可以为文本输入框设置校验条件。如果用户的输入不符合条件，就无法将字符输入文本框。
    Event.stopPropagation()：阻止事件在 DOM 中继续传播，防止再触发定义在别的节点上的监听函数，
      但是不包括在当前节点上其他的事件监听函数。
    Event.stopImmediatePropagation方法阻止同一个事件的其他监听函数被调用，不管监听函数定义在当前节点还是其他节点。
    Event.composedPath()返回一个数组，成员是事件的最底层节点和依次冒泡经过的所有上层节点。
</pre>
      </div>

      <!-- 鼠标事件 -->
      <div class="chapter" id='kp44'>
        <h2>kp44 鼠标事件</h2>
        <pre>
  1、鼠标事件指与鼠标相关的事件，继承了MouseEvent接口。
    ·click：按下鼠标（通常是按下主按钮）时触发。
      用户在同一个位置先完成mousedown动作，再完成mouseup动作。
    ·dblclick：在同一个元素上双击鼠标时触发。
    ·mousedown：按下鼠标键时触发。
    ·mouseup：释放按下的鼠标键时触发。
    ·mousemove：当鼠标在一个节点内部移动时触发。当鼠标持续移动时，该事件会连续触发。
      为了避免性能问题，建议对该事件的监听函数做一些限定，比如限定一段时间内只能运行一次。
    ·mouseenter：鼠标进入一个节点时触发，进入子节点不会触发这个事件。
    ·mouseover：鼠标进入一个节点时触发，进入子节点会再一次触发这个事件。
    ·mouseout：鼠标离开一个节点时触发，离开父节点也会触发这个事件。
    ·mouseleave：鼠标离开一个节点时触发，离开父节点不会触发这个事件。
    ·contextmenu：按下鼠标右键时（上下文菜单出现前）触发，或者按下“上下文菜单键”时触发。
    ·wheel：滚动鼠标的滚轮时触发，该事件继承的是WheelEvent接口。
    触发顺序是，mousedown首先触发，mouseup接着触发，click最后触发。
    dblclick事件则会在mousedown、mouseup、click之后触发。
    mouseover事件和mouseenter事件，都是鼠标进入一个节点时触发
    mouseenter事件只触发一次，而只要鼠标在节点内部移动，mouseover事件会在子节点上触发多次。
    在父元素内部离开一个子元素时，mouseleave事件不会触发，而mouseout事件会触发。
  2、MouseEvent接口的实例属性
    ·MouseEvent.altKey、MouseEvent.ctrlKey、MouseEvent.metaKey、MouseEvent.shiftKey
      这四个属性都返回一个布尔值，表示事件发生时，是否按下对应的键。它们都是只读属性。
    ·MouseEvent.button属性返回一个数值，表示事件发生时按下了鼠标的哪个键。该属性只读。
      0：按下主键（通常是左键）、1：按下辅助键（通常是中键或者滚轮键）、2：按下次键（通常是右键）
    ·MouseEvent.buttons属性返回一个三个比特位的值，表示同时按下了哪些键。
      1：二进制为001（十进制的1），表示按下左键。
      2：二进制为010（十进制的2），表示按下右键。
      4：二进制为100（十进制的4），表示按下中键或滚轮键。
    ·MouseEvent.clientX属性返回鼠标位置相对于浏览器窗口左上角的水平坐标（单位像素），别名 MouseEvent.x。
    ·MouseEvent.clientY属性返回垂直坐标。这两个属性都是只读属性。别名 MouseEvent.y。
    ·MouseEvent.movementX属性返回当前位置与上一个mousemove事件之间的水平距离（单位像素）。只读
    ·MouseEvent.movementY属性返回当前位置与上一个mousemove事件之间的垂直距离（单位像素）。只读
    ·MouseEvent.screenX属性返回鼠标位置相对于屏幕左上角的水平坐标（单位像素），
    ·MouseEvent.screenY属性返回垂直坐标。这两个属性都是只读属性。
    ·MouseEvent.offsetX属性返回鼠标位置与目标节点左侧的padding边缘的水平距离（单位像素），
    ·MouseEvent.offsetY属性返回与目标节点上方的padding边缘的垂直距离。这两个属性都是只读属性。
    ·MouseEvent.pageX属性返回鼠标位置与文档左侧边缘的距离（单位像素），返回值包括文档不可见的部分。只读。
    ·MouseEvent.pageY属性返回与文档上侧边缘的距离（单位像素）。返回值包括文档不可见的部分。只读。
    ·MouseEvent.relatedTarget属性返回事件的相关节点。对于那些没有相关节点的事件，该属性返回null。只读。
  3、MouseEvent 接口的实例方法
    ·MouseEvent.getModifierState方法返回一个布尔值，表示有没有按下特定的功能键。
  4、WheelEvent 接口继承了 MouseEvent 实例，代表鼠标滚轮事件的实例对象。
</pre>
      </div>

      <!-- 键盘事件 -->
      <div class="chapter" id='kp45'>
        <h2>kp45 键盘事件</h2>
        <pre>
  1、键盘事件由用户击打键盘触发，主要有keydown、keypress、keyup三个事件，它们都继承了KeyboardEvent接口。
    keydown：按下键盘时触发。
    keypress：按下有值的键时触发，即按下 Ctrl、Alt、Shift、Meta 这样无值的键，这个事件不会触发。
      对于有值的键，按下时先触发keydown事件，再触发这个事件。
    keyup：松开键盘时触发该事件。
  2、KeyboardEvent接口用来描述用户与键盘的互动。这个接口继承了Event接口
  3、KeyboardEvent 的实例属性
    ·KeyboardEvent.altKey：是否按下 Alt 键 只读。
    ·KeyboardEvent.ctrlKey：是否按下 Ctrl 键 只读。
    ·KeyboardEvent.metaKey：是否按下 meta 键（Mac 系统是一个四瓣的小花，Windows 系统是 windows 键）只读。
    ·KeyboardEvent.shiftKey：是否按下 Shift 键 只读。
    ·KeyboardEvent.code属性返回一个字符串，表示当前按下的键的字符串形式。该属性只读。
    ·KeyboardEvent.key属性返回一个字符串，表示按下的键名。该属性只读。
    ·KeyboardEvent.location属性返回一个整数，表示按下的键处在键盘的哪一个区域。
    ·KeyboardEvent.repeat返回一个布尔值，代表该键是否被按着不放，以便判断是否重复这个键，
      即浏览器会持续触发keydown和keypress事件，直到用户松开手为止。
  4、KeyboardEvent 的实例方法
    ·KeyboardEvent.getModifierState()方法返回一个布尔值，表示是否按下或激活指定的功能键。
      常用参数：Alt：Alt键、CapsLock：大写锁定键、Control：Ctrl键、Meta：Meta键、NumLock：数字键盘开关键、Shift：Shift键
</pre>
      </div>

      <!-- 进度事件 -->
      <div class="chapter" id='kp46'>
        <h2>kp46 进度事件</h2>
        <pre>
  1、进度事件用来描述资源加载的进度，继承了ProgressEvent接口。
    主要由 AJAX 请求、< im g>、< audi o>、< vide o>、< styl e>、< lin k>等外部资源的加载触发，
      abort：外部资源中止加载时（比如用户取消）触发。如果发生错误导致中止，不会触发该事件。
      error：由于错误导致外部资源无法加载时触发。
      load：外部资源加载成功时触发。
      loadstart：外部资源开始加载时触发。
      loadend：外部资源停止加载时触发，发生顺序排在error、abort、load等事件的后面。
      progress：外部资源加载过程中不断触发。
      timeout：加载超时时触发。
    注意，除了资源下载，文件上传也存在这些事件。
    有时，图片加载会在脚本运行之前就完成，脚本放置在网页底部的时候，有可能load和error事件的监听函数根本不会执行。
    所以，比较可靠的方式，是用complete属性先判断一下是否加载完成。
  2、ProgressEvent接口主要用来描述外部资源加载的进度，比如 AJAX 加载、< img>、< video>、< styl e>、< link>等外部资源加载。
    ProgressEvent具有对应的实例属性：
      ProgressEvent.lengthComputable、ProgressEvent.loaded、ProgressEvent.total
</pre>
      </div>

      <!-- 表单事件 -->
      <div class="chapter" id='kp47'>
        <h2>kp47 表单事件</h2>
        <pre>
  1、表单事件的种类
    1）input事件：当< input>、< select>、< textarea>的值发生变化时触发
      复选框checkbox或单选框radio，用户改变选项时，也会触发这个事件
      对于打开contenteditable属性的元素，只要值发生变化，也会触发input事件。
      input事件的一个特点，就是会连续触发，比如用户每按下一次按键，就会触发一次input事件。
    2）select事件当在input、textarea里面选中文本时触发。
      选中的文本可以通过event.target元素的selectionDirection、selectionEnd、selectionStart和value属性拿到。
    3）change事件当input、select、textarea的值发生变化时触发。
      与input事件的最大不同，就是不会连续触发，只有全部修改完成时才会触发，另一方面input事件必然伴随change事件。
    4）用户提交表单时，如果表单元素的值不满足校验条件，就会触发invalid事件。
    5）reset事件当表单重置（所有表单成员变回默认值）时触发。
    6）submit事件当表单数据向服务器提交时触发。
  2、InputEvent接口主要用来描述input事件的实例。
    ·InputEvent.data属性返回一个字符串，表示变动的内容。
    ·InputEvent.inputType属性返回一个字符串，表示字符串发生变更的类型。
    ·InputEvent.dataTransfer属性返回一个 DataTransfer 实例。
      只在文本框接受粘贴内容（insertFromPaste）或拖拽内容（insertFromDrop）时才有效。
</pre>
      </div>

      <!-- 触摸事件 -->
      <div class="chapter" id='kp48'>
        <h2>kp48 触摸事件</h2>
        <pre>
  1、浏览器的触摸 API 由三个部分组成。
    Touch：一个触摸点、TouchList：多个触摸点的集合、TouchEvent：触摸引发的事件实例
  2、Touch 接口代表单个触摸点。触摸点可能是一根手指，也可能是一根触摸笔。
  3、TouchList接口表示一组触摸点的集合。它的实例是一个类似数组的对象，成员是Touch的实例对象，表示所有触摸点。
  4、TouchEvent 接口继承了 Event 接口，表示由触摸引发的事件实例，通常来自触摸屏或轨迹板。
  5、触摸事件的种类，可以通过TouchEvent.type属性，查看到底发生的是哪一种事件。
    touchstart：用户开始触摸时触发，它的target属性返回发生触摸的元素节点。
    touchend：用户不再接触触摸屏时触发，它的target属性与touchstart事件一致的，就是开始触摸时所在的元素节点。
      它的changedTouches属性返回一个TouchList实例，包含所有不再触摸的触摸点（即Touch实例对象）。
    touchmove：用户移动触摸点时触发，它的target属性与touchstart事件一致。
      如果触摸的半径、角度、力度发生变化，也会触发该事件。
    touchcancel：触摸点取消时触发，比如在触摸区域跳出一个模态窗口（modal window）、
      触摸点离开了文档区域（进入浏览器菜单栏）、用户的触摸点太多，超过了支持的上限（自动取消早先的触摸点）。
</pre>
      </div>

      <!-- 拖拉事件 -->
      <div class="chapter" id='kp49'>
        <h2>kp49 拖拉事件</h2>
        <pre>
  1、拖拉（drag）指的是，用户在某个对象上按下鼠标键不放，拖动它到另一个位置，然后释放鼠标键，将该对象放在那里。
    为了让元素节点可拖拉，可以将该节点的draggable属性设为true。
    注意，一旦某个元素节点的draggable属性设为true，就无法再用鼠标选中该节点内部的文字或子节点了。
  2、DataTransfer的实例对象用来读写拖拉事件中传输的数据
  3、其他事件
</pre>
      </div>

      <!-- 浏览器环境概述 -->
      <div class="chapter" id='kp50'>
        <h2>kp50 浏览器环境概述</h2>
        <pre>
  1、代码嵌入网页的方法
    1）script 元素嵌入代码：< scrip t>元素内部可以直接写 JavaScript 代码。
      对 JavaScript 脚本来说，type属性可以设为两种值：
        ·text/javascript：这是默认值，也是历史上一贯设定的值。
        ·application/javascript：对于较新的浏览器，建议设为这个值。
    2）script 元素加载外部脚本，< scrip t>标签也可以指定加载外部的脚本文件。
      加载外部脚本和直接添加代码块，这两种方法不能混用。
      为防止攻击者篡改外部脚本，script标签允许设置一个integrity属性，写入外部脚本Hash签名，来验证脚本的一致性。
    3）事件属性：网页元素的事件属性（比如onclick和onmouseover），可以写入JavaScript代码
    4）URL协议：URL支持javascript:协议，即在URL的位置写入代码，使用这个URL的时候就会执行JavaScript代码。
      浏览器的地址栏也可以执行javascript:协议。
      javascript:协议的常见用途是书签脚本Bookmarklet。浏览器的书签保存的是一个网址
      为了防止书签替换掉当前文档，可以在脚本前加上void，或者在脚本最后加上void 0。
  2、script元素
    浏览器加载 JavaScript 脚本，主要通过script元素完成。正常的网页加载流程是这样的。
      ·浏览器一边下载 HTML 网页，一边开始解析。也就是说，不等到下载完，就开始解析。
      ·解析过程中，浏览器发现script元素，就暂停解析，把网页渲染的控制权转交给JavaScript引擎。
      ·如果script元素引用了外部脚本，就下载该脚本再执行，否则就直接执行代码。
      ·JavaScript 引擎执行完毕，控制权交还渲染引擎，恢复往下解析 HTML 网页。
    加载外部脚本时，浏览器会暂停页面渲染，等待脚本下载并执行完成后，再继续渲染。
    如果外部脚本加载时间很长，浏览器就一直等待脚本下载完成，网页长时间失去响应，浏览器呈现“假死”状态，被称为“阻塞效应”。
    为了避免这种情况，较好的做法是将script标签都放在页面底部，而不是头部。
    对于来自同一个域名的资源，比如脚本文件、样式表文件、图片文件等，浏览器一般有限制，同时最多下载6～20个资源，
      即最多同时打开的 TCP 连接有限制，这是为了防止对服务器造成太大压力。
    如果是来自不同域名的资源，就没有这个限制。所以，通常把静态文件放在不同的域名之下，以加快下载速度。
    浏览器会同时并行下载js文件，但是，执行时会保证按出现顺序执行js，即使后者先下载完成
  3、为了解决脚本文件下载阻塞网页渲染的问题，一个方法是对script元素加入defer属性
      作用是延迟脚本的执行，等到 DOM 加载生成后，再执行脚本。
    defer属性的运行流程如下：
      ·浏览器开始解析 HTML 网页。
      ·解析过程中，发现带有defer属性的script元素。
      ·浏览器继续往下解析 HTML 网页，同时并行下载script元素加载的外部脚本。
      ·浏览器完成解析 HTML 网页，此时再回过头执行已经下载完成的脚本。
    对于内置而不是加载外部脚本的script标签，以及动态生成的script标签，defer属性不起作用。
    使用defer加载的外部脚本不应该使用document.write方法。
  4、async 属性：解决“阻塞效应”的另一个方法是对script元素加入async属性。
    async属性的作用是，使用另一个进程下载脚本，下载时不会阻塞渲染。
      ·浏览器开始解析 HTML 网页。
      ·解析过程中，发现带有async属性的script标签。
      ·浏览器继续往下解析 HTML 网页，同时并行下载script标签中的外部脚本。
      ·脚本下载完成，浏览器暂停解析 HTML 网页，开始执行下载的脚本。
      ·脚本执行完毕，浏览器恢复解析 HTML 网页。
    async属性可以保证脚本下载的同时，浏览器继续渲染
    注意，一旦采用这个属性，就无法保证脚本的执行顺序。哪个脚本先下载结束，就先执行那个脚本。
    使用async属性的脚本文件里面的代码，不应该使用document.write方法。
    一般来说，如果脚本之间没有依赖关系，就使用async属性，如果脚本之间有依赖关系，就使用defer属性。
    如果同时使用async和defer属性，后者不起作用，浏览器行为由async属性决定。
  5、脚本的动态加载：script元素还可以动态生成，生成后再插入页面，从而实现脚本的动态加载。
    为动态加载的脚本指定回调函数
    如果不指定协议，浏览器默认采用 HTTP 协议下载。如果要采用 HTTPS 协议下载，必需写明。
    根据页面本身的协议来决定加载协议，这时可以采用下面的写法。
  6、浏览器的核心是两部分：渲染引擎和 JavaScript 解释器（又称 JavaScript 引擎）。
    1）渲染引擎的主要作用是，将网页代码渲染为用户视觉可以感知的平面文档。不同的浏览器有不同的渲染引擎。
      渲染引擎处理网页，通常分成四个阶段：
        ·解析代码：HTML 代码解析为 DOM，CSS 代码解析为 CSSOM（CSS Object Model）。
        ·对象合成：将 DOM 和 CSSOM 合成一棵渲染树（render tree）。
        ·布局：计算出渲染树的布局（layout）。
        ·绘制：将渲染树绘制到屏幕。
      以上四步并非严格按顺序执行，往往第一步还没完成，第二步和第三步就已经开始了。
    2）重流和重绘
      渲染树转换为网页布局，称为“布局流”（flow）；布局显示到页面的这个过程，称为“绘制”（paint）。
      页面生成以后，脚本操作和样式表操作，都会触发“重流”（reflow）和“重绘”（repaint）
      用户的互动也会触发重流和重绘，
      重流和重绘并不一定一起发生，重流必然导致重绘，重绘不一定需要重流。
      开发者，应该尽量设法降低重绘的次数和成本。
        比如，尽量不要变动高层的 DOM 元素，而以底层 DOM 元素的变动代替；
        再比如，重绘table布局和flex布局，开销都会比较大。
      优化技巧：
        ·读取DOM或者写入DOM，尽量写在一起，不要混杂。不要读取一个DOM节点，然后立刻写入，接着再读取一个DOM节点。
        ·缓存 DOM 信息。
        ·不要一项一项地改变样式，而是使用 CSS class 一次性改变样式。
        ·使用documentFragment操作 DOM
        ·动画使用absolute定位或fixed定位，这样可以减少对其他元素的影响。
        ·只在必要时才显示隐藏元素。
        ·使用window.requestAnimationFrame()，因为它可以把代码推迟到下一次重流时执行，而不是立即要求页面重流。
        ·使用虚拟 DOM（virtual DOM）库。
    3）JavaScript 引擎的主要作用是，读取网页中的 JavaScript 代码，对其处理后运行。
      JavaScript 是一种解释型语言，也就是说，它不需要编译，由解释器实时运行。
      好处是运行和修改都比较方便，刷新页面就可以重新解释；
      缺点是每次运行都要调用解释器，系统开销较大，运行速度慢于编译型语言。
      为提高运行速度，目前的浏览器都将js进行一定程度的编译，生成类似字节码的中间代码，以提高运行速度。
      早期，浏览器内部对 JavaScript 的处理过程如下：
        ·读取代码，进行词法分析（Lexical analysis），将代码分解成词元（token）。
        ·对词元进行语法分析（parsing），将代码整理成“语法树”（syntax tree）。
        ·使用“翻译器”（translator），将代码转为字节码（bytecode）。
        ·使用“字节码解释器”（bytecode interpreter），将字节码转为机器码。
      为了提高运行速度，现代浏览器改为采用“即时编译”（Just In Time compiler，缩写 JIT），
        即字节码只在运行时编译，用到哪一行就编译哪一行，并且把编译结果缓存（inline cache）
      字节码不能直接运行，而是运行在一个虚拟机（Virtual Machine）之上，一般也把虚拟机称为 JavaScript 引擎。
</pre>
      </div>

      <!-- window对象 -->
      <div class="chapter" id='kp51'>
        <h2>kp51 window对象</h2>
        <pre>
  1、浏览器里面，window对象（注意，w为小写）指当前的浏览器窗口。
    也是当前页面的顶层对象，即最高一层的对象，所有其他对象都是它的下属。
    一个变量如果未声明，那么默认就是顶层对象的属性。
  2、window 对象的属性
    ·name属性是一个字符串，表示当前浏览器窗口的名字。
      窗口不一定需要名字，这个属性主要配合超链接和表单的target属性使用。
      只要浏览器窗口不关闭，这个属性是不会消失的。
    ·closed属性返回一个布尔值，表示窗口是否关闭。一般用来检查，使用脚本打开的新窗口是否关闭。
    ·opener属性表示打开当前窗口的父窗口。如果当前窗口没有父窗口，则返回null。
      如果两个窗口之间不需要通信，建议将子窗口的opener属性显式设为null，这样可以减少一些安全隐患。
    ·window.self和window.window属性都指向窗口本身。这两个属性只读。
    ·frames属性返回一个类似数组的对象，成员为页面内所有框架窗口，包括frame元素和iframe元素。
      frames属性实际上是window对象的别名。
    ·length属性返回当前网页包含的框架总数。如果当前网页不包含frame和iframe元素，window.length就返回0。
      window.frames.length与window.length应该是相等的。
    ·frameElement属性主要用于当前窗口嵌在另一个网页的情况，返回当前窗口所在的那个元素节点。
    ·top属性指向最顶层窗口，主要用于在框架窗口（frame）里面获取顶层窗口。不包含框架的网页，等同于window对象。
    ·parent属性指向父窗口。如果当前窗口没有父窗口，window.parent指向自身。
    ·status属性用于读写浏览器状态栏的文本。
    ·devicePixelRatio属性返回一个数值，表示一个 CSS 像素的大小与一个物理像素的大小之间的比率。
      表示一个 CSS 像素由多少个物理像素组成。
      如果这个比率较大，就表示用户正在使用高清屏幕，因此可以显示较大像素的图片。
    ·screenX和screenY属性，返回浏览器窗口左上角相对于当前屏幕左上角的水平距离和垂直距离（像素）。只读。
    ·innerHeight和innerWidth属性，返回网页在当前窗口中可见部分的高度和宽度，即“视口”（viewport）的大小（像素）。只读。
    ·outerHeight和window.outerWidth属性返回浏览器窗口的高度和宽度，包括浏览器菜单和边框（像素）。只读。
    ·scrollX属性返回页面的水平滚动距离，scrollY属性返回页面的垂直滚动距离，单位像素。只读。
      返回值不是整数，而是双精度浮点数。如果页面没有滚动，它们的值就是0。
      pageXOffset属性和pageYOffset属性，是window.scrollX和window.scrollY别名。
    ·组件属性：组件属性返回浏览器的组件对象。这样的属性有下面几个。
      ·window.locationbar：地址栏对象
      ·window.menubar：菜单栏对象
      ·window.scrollbars：窗口的滚动条对象
      ·window.toolbar：工具栏对象
      ·window.statusbar：状态栏对象
      ·window.personalbar：用户安装的个人工具栏对象
    ·全局对象属性指向一些浏览器原生的全局对象。
    ·isSecureContext属性返回一个布尔值，表示当前窗口是否处在加密环境。如果是 HTTPS 协议，就是true，否则就是false。
  3、window 对象的方法
    ·alert()方法弹出的对话框，只有一个“确定”按钮，往往用来通知用户某些信息。
    ·prompt()方法弹出的对话框，提示文字的下方，还有一个输入框，要求用户输入信息，并有“确定”和“取消”两个按钮。
      用来获取用户输入的数据。最好总是提供第二个参数，作为输入框的默认值。
    ·confirm()方法弹出的对话框，除了提示信息之外，只有“确定”和“取消”两个按钮，往往用来征询用户是否同意。
    三个方法都具有堵塞效应，一旦弹出对话框，整个页面就是暂停执行，等待用户做出反应。都是浏览器统一规定的式样，无法定制。
    ·open方法用于新建另一个浏览器窗口，类似于浏览器菜单的新建窗口选项。返回新窗口的引用，如果无法新建窗口，则返回null。
      url：字符串，表示新窗口的网址。如果省略，默认网址就是about:blank。
      windowName：字符串，表示新窗口的名字。如果该名字的窗口已经存在，则占用该窗口，不再新建窗口。
        如果省略，就默认使用_blank，表示新建一个没有名字的窗口。
        预设值，_self表示当前窗口，_top表示顶层窗口，_parent表示上一层窗口。
      windowFeatures：字符串，内容为逗号分隔的键值对，表示新窗口的参数。
        如果省略，则默认打开一个完整 UI 的新窗口。
        如果新建的是一个已经存在的窗口，则该参数不起作用，浏览器沿用以前窗口的参数。
      window.open方法返回新窗口的引用。
      注意，如果新窗口和父窗口不是同源的（即不在同一个域），它们彼此不能获取对方窗口对象的内部属性。
    ·close方法用于关闭当前窗口，一般只用来关闭window.open方法新建的窗口。
      该方法只对顶层窗口有效，iframe框架之中的窗口使用该方法无效。
    ·stop()方法完全等同于单击浏览器的停止按钮，会停止加载图像、视频等正在或等待加载的对象。
    ·moveTo()：用于移动浏览器窗口到指定位置。接受两个参数，分别是窗口左上角距离屏幕左上角的水平距离和垂直距离，像素。
    ·moveBy()：将窗口移动到一个相对位置。接受两个参数，分别是窗口左上角向右移动的水平距离和向下移动的垂直距离，像素。
    ·resizeTo()方法用于缩放窗口到指定大小。两个参数，缩放后的窗口宽度、缩放后的窗口高度。
    ·window.resizeBy()：用于缩放窗口。按照相对的量缩放，需要给出缩放后的绝对大小。
      它接受两个参数，第一个是水平缩放的量，第二个是垂直缩放的量，单位都是像素。
    ·scrollTo方法用于将文档滚动到指定位置。它接受两个参数，表示滚动后位于窗口左上角的页面坐标。
      或者接受一个配置对象作为参数。配置对象options有三个属性：
        top：滚动后页面左上角的垂直坐标，即 y 坐标。
        left：滚动后页面左上角的水平坐标，即 x 坐标。
        behavior：字符串，表示滚动的方式，有三个可能值（smooth、instant、auto），默认值为auto。
      scroll()方法是window.scrollTo()方法的别名。
    ·scrollBy()方法用于将网页滚动指定距离（单位像素）。它接受两个参数：水平向右滚动的像素，垂直向下滚动的像素。
      将网页向下滚动一屏。window.scrollBy(0, window.innerHeight)
      如果不是要滚动整个文档，而是要滚动某个元素，可以使用下面三个属性和方法。
        Element.scrollTop、Element.scrollLeft、Element.scrollIntoView()
    ·print方法会跳出打印对话框，与用户点击菜单里面的“打印”命令效果相同。
    ·focus()方法会激活窗口，使其获得焦点，出现在其他窗口的前面。
    ·blur()方法将焦点从窗口移除。
    当前窗口获得焦点时，会触发focus事件；当前窗口失去焦点时，会触发blur事件。
    ·getSelection方法返回一个Selection对象，表示用户现在选中的文本。
      使用Selection对象的toString方法可以得到选中的文本。
    ·getComputedStyle()方法接受一个元素节点作为参数，返回一个包含该元素的最终样式信息的对象，
    ·matchMedia()方法用来检查 CSS 的mediaQuery语句，
    ·requestAnimationFrame()方法跟setTimeout类似，都是推迟某个函数的执行。
      setTimeout必须指定推迟的时间，requestAnimationFrame()则是推迟到浏览器下一次重流时执行，执行完才会进行下一次重绘。
      重绘通常是16ms执行一次，浏览器自动调节速率，比如网页切换到后台Tab页时，requestAnimationFrame()会暂停执行。
      该方法接受一个回调函数callback作为参数。
      callback执行时，参数是系统传入的一个高精度时间戳（performance.now()的返回值），单位毫秒，表示距离网页加载的时间。
      requestAnimationFrame()的返回值是一个整数，可以传入window.cancelAnimationFrame()，用来取消回调函数的执行。
    ·requestIdleCallback()跟setTimeout类似，也是将某个函数推迟执行，但是它保证将回调函数推迟到系统资源空闲时执行。
      也就是说，如果某个任务不是很关键，可以使用requestIdleCallback()将其推迟执行，以保证网页性能。
  4、window对象事件
    ·load事件发生在文档在浏览器窗口加载完毕时。
    ·浏览器脚本发生错误时，会触发window对象的error事件。
  5、多窗口操作
    网页可以使用iframe元素，嵌入其他网页，因此一个网页之中会形成多个窗口。如果子窗口之中又嵌入别的网页，就会形成多级窗口。
    窗口的引用：各个窗口之中的脚本，可以引用其他窗口。
      top：顶层窗口，即最上层的那个窗口、parent：父窗口、self：当前窗口，即自身
</pre>
      </div>

      <!-- cookie -->
      <div class="chapter" id='kp52'>
        <h2>kp52 cookie</h2>
        <pre>
  1、Cookie是服务器保存在浏览器的一小段文本信息，一般大小不能超过4KB。浏览器每次向服务器发出请求，就会自动附上这段信息。
</pre>
      </div>

      <div class="chapter" id='kp53'>
        <h2>kp53 </h2>
        <pre>
        </pre>
      </div>



    </div>
    <!-- -----------------------------目录----------------------------- -->
    <div class="catalog-box" id="catalog">
      <ol>
        <li v-for="(c,index) in reverseCatalogs">
          <a :href="getCatalogId(index)">kp{{ index + 1}} {{ c }}</a>
        </li>
      </ol>
    </div>
    <script type="text/javascript">
      const catalogs = [
        "cookie",
        "window对象",
        "浏览器环境概述",
        "拖拉事件",
        "触摸事件",
        "表单事件",
        "进度事件",
        "键盘事件",
        "鼠标事件",
        "Event对象",
        "事件模型",
        "EventTarget接口",
        "Mutation Observer API",
        "CSS操作",
        "Text节点和DocumentFragment节点",
        "属性的操作",
        "Element节点",
        "Document节点",
        "ParentNode接口，ChildNode接口",
        "NodeList接口，HTMLCollection接口",
        "Node接口",
        "DOM概述",
        "Promise对象",
        "定时器",
        "异步操作概述",
        "严格模式",
        "Object对象的相关方法",
        "对象的继承",
        "this关键字",
        "实例对象与new命令",
        "js标准库：JSON对象",
        "js标准库：RegExp对象",
        "js标准库：Date对象",
        "js标准库：Math对象",
        "js标准库：包装对象",
        "js标准库：Array对象",
        "js标准库：属性描述对象",
        "js标准库：Object",
        "js的console对象与控制台",
        "js的编码风格",
        "js的错误处理机制",
        "js的数据类型转换",
        "js的运算符",
        "js的数组",
        "js的函数",
        "js的对象",
        "js的字符串",
        "js的数值类型",
        "js的null和undefined",
        "js数据类型",
        "js基本语法",
        "call、apply、bind方法",
        // "在此写目录"
      ];
      const catalogVM = new Vue({
        el: '#catalog',
        data: {
          catalogs, // 对象增强写法
          currId: 1,
        },
        computed: {
          reverseCatalogs() {
            return this.catalogs.reverse();
          },
        },
        methods: {
          // 获取id
          getCatalogId(index) {
            return '#kp' + (index + 1);
          },
        },
      });
    </script>
  </div>
</body>

</html>